Fix check when we cache the samples. Clean up.
[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    3
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
146         event_do(&data_ready);
147 }
148
149 static void sam3_i2s_txWait(I2s *i2s)
150 {
151         (void)i2s;
152         event_wait(&data_ready);
153 }
154
155 static void i2s_dmac_irq(uint32_t status)
156 {
157         if (i2s_status & I2S_STATUS_SINGLE_TRASF)
158         {
159                 i2s_status &= ~I2S_STATUS_SINGLE_TRASF;
160         }
161         else
162         {
163                 if (status & (BV(I2S_DMAC_CH) << DMAC_EBCIDR_ERR0))
164                 {
165                         i2s_status |= I2S_STATUS_ERR;
166                         // Disable to reset channel and clear fifo
167                         dmac_stop(I2S_DMAC_CH);
168                 }
169                 else
170                 {
171                         prev = curr;
172                         curr = next;
173                         next = prev;
174
175                         if (i2s_status & I2S_STATUS_TX)
176                         {
177                                 curr->src_addr = (uint32_t)&sample_buff[next_idx];
178                                 curr->dst_addr = (uint32_t)&SSC_THR;
179                                 curr->dsc_addr = (uint32_t)next;
180                                 curr->ctrla    = I2S_TX_DMAC_CTRLA | ((chunk_size / I2S_WORD_BYTE_SIZE) & 0xffff);
181                                 curr->ctrlb    = I2S_TX_DMAC_CTRLB & ~BV(DMAC_CTRLB_IEN);
182                         }
183                         else
184                         {
185                                 curr->src_addr = (uint32_t)&SSC_RHR;
186                                 curr->dst_addr = (uint32_t)&sample_buff[next_idx];
187                                 curr->dsc_addr = (uint32_t)next;
188                                 curr->ctrla    = I2S_RX_DMAC_CTRLA | ((chunk_size / I2S_WORD_BYTE_SIZE) & 0xffff);
189                                 curr->ctrlb    = I2S_RX_DMAC_CTRLB & ~BV(DMAC_CTRLB_IEN);
190                         }
191
192                 }
193         }
194         event_do(&data_ready);
195 }
196
197
198 static void sam3_i2s_txStart(I2s *i2s, void *buf, size_t len, size_t slice_len)
199 {
200         ASSERT(buf);
201         ASSERT(len >= slice_len);
202         ASSERT(!(len % slice_len));
203
204         i2s_status &= ~(I2S_STATUS_END_TX | I2S_STATUS_SINGLE_TRASF);
205
206         sample_buff = (uint8_t *)buf;
207         next_idx = 0;
208         chunk_size = slice_len;
209         size_t remaing_size = len;
210         transfer_size = len;
211
212
213         memset(&lli0, 0, sizeof(DmacDesc));
214         memset(&lli1, 0, sizeof(DmacDesc));
215
216         prev = 0;
217         curr = &lli1;
218         next = &lli0;
219
220         for (int i = 0; i < I2S_CACHED_CHUNK_SIZE; i++)
221         {
222                 prev = curr;
223                 curr = next;
224                 next = prev;
225
226                 i2s->ctx.tx_callback(i2s, &sample_buff[next_idx], chunk_size);
227
228                 curr->src_addr = (uint32_t)&sample_buff[next_idx];
229                 curr->dst_addr = (uint32_t)&SSC_THR;
230                 curr->dsc_addr = (uint32_t)next;
231                 curr->ctrla    = I2S_TX_DMAC_CTRLA | ((chunk_size / I2S_WORD_BYTE_SIZE) & 0xffff);
232                 curr->ctrlb    = I2S_TX_DMAC_CTRLB & ~BV(DMAC_CTRLB_IEN);
233
234                 remaing_size -= chunk_size;
235                 next_idx += chunk_size;
236
237                 if (chunk_size >= remaing_size)
238                         break;
239
240         }
241
242         dmac_setLLITransfer(I2S_DMAC_CH, prev, I2S_TX_DMAC_CFG);
243
244         if (dmac_start(I2S_DMAC_CH) < 0)
245         {
246                 LOG_ERR("DMAC start[%x]\n", dmac_error(I2S_DMAC_CH));
247                 return;
248         }
249
250         i2s_status &= ~I2S_STATUS_ERR;
251         i2s_status |= I2S_STATUS_TX;
252
253         SSC_CR = BV(SSC_TXEN);
254
255         while (1)
256         {
257                 event_wait(&data_ready);
258                 I2S_STROBE_ON();
259                 remaing_size -= chunk_size;
260                 next_idx += chunk_size;
261
262                 if (remaing_size <= 0)
263                 {
264                         remaing_size = transfer_size;
265                         next_idx = 0;
266                 }
267
268                 if (i2s_status & I2S_STATUS_ERR)
269                 {
270                         LOG_ERR("Error while streaming.\n");
271                         break;
272                 }
273
274                 if (i2s_status & I2S_STATUS_END_TX)
275                 {
276                         LOG_INFO("Stop streaming.\n");
277                         break;
278                 }
279
280                 i2s->ctx.tx_callback(i2s, &sample_buff[next_idx], chunk_size);
281                 I2S_STROBE_OFF();
282         }
283 }
284
285 static void sam3_i2s_rxStop(I2s *i2s)
286 {
287         (void)i2s;
288         SSC_CR = BV(SSC_RXDIS) | BV(SSC_TXDIS);
289         dmac_stop(I2S_DMAC_CH);
290
291         i2s_status |= I2S_STATUS_END_RX;
292         next_idx = 0;
293         transfer_size = 0;
294
295         i2s_status &= ~I2S_STATUS_RX;
296
297         event_do(&data_ready);
298 }
299
300 static void sam3_i2s_rxWait(I2s *i2s)
301 {
302         (void)i2s;
303         event_wait(&data_ready);
304 }
305
306 static void sam3_i2s_rxStart(I2s *i2s, void *buf, size_t len, size_t slice_len)
307 {
308         ASSERT(buf);
309         ASSERT(len >= slice_len);
310         ASSERT(!(len % slice_len));
311
312         i2s_status &= ~(I2S_STATUS_END_RX | I2S_STATUS_SINGLE_TRASF);
313
314         sample_buff = (uint8_t *)buf;
315         next_idx = 0;
316         chunk_size = slice_len;
317         size_t remaing_size = len;
318         transfer_size = len;
319
320         memset(&lli0, 0, sizeof(DmacDesc));
321         memset(&lli1, 0, sizeof(DmacDesc));
322
323         prev = 0;
324         curr = &lli1;
325         next = &lli0;
326
327         for (int i = 0; i < I2S_CACHED_CHUNK_SIZE; i++)
328         {
329                 prev = curr;
330                 curr = next;
331                 next = prev;
332
333                 curr->src_addr = (uint32_t)&SSC_RHR;
334                 curr->dst_addr = (uint32_t)&sample_buff[next_idx];
335                 curr->dsc_addr = (uint32_t)next;
336                 curr->ctrla    = I2S_RX_DMAC_CTRLA | ((chunk_size / I2S_WORD_BYTE_SIZE) & 0xffff);
337                 curr->ctrlb    = I2S_RX_DMAC_CTRLB & ~BV(DMAC_CTRLB_IEN);
338
339                 remaing_size -= chunk_size;
340                 next_idx += chunk_size;
341
342                 if (chunk_size >= remaing_size)
343                         break;
344         }
345
346         dmac_setLLITransfer(I2S_DMAC_CH, prev, I2S_RX_DMAC_CFG);
347
348         if (dmac_start(I2S_DMAC_CH) < 0)
349         {
350                 LOG_ERR("DMAC start[%x]\n", dmac_error(I2S_DMAC_CH));
351                 return;
352         }
353
354         i2s_status &= ~I2S_STATUS_ERR;
355         i2s_status |= I2S_STATUS_RX;
356
357         SSC_CR = BV(SSC_TXEN) | BV(SSC_RXEN);
358
359         while (1)
360         {
361                 event_wait(&data_ready);
362                 I2S_STROBE_ON();
363                 i2s->ctx.rx_callback(i2s, &sample_buff[next_idx], chunk_size);
364
365                 remaing_size -= chunk_size;
366                 next_idx += chunk_size;
367
368                 if (remaing_size <= 0)
369                 {
370                         remaing_size = transfer_size;
371                         next_idx = 0;
372                 }
373
374                 if (i2s_status & I2S_STATUS_ERR)
375                 {
376                         LOG_ERR("Error while streaming.\n");
377                         break;
378                 }
379
380                 if (i2s_status & I2S_STATUS_END_RX)
381                 {
382                         LOG_INFO("Stop streaming.\n");
383                         break;
384                 }
385                 I2S_STROBE_OFF();
386         }
387 }
388
389
390 static bool sam3_i2s_isTxFinish(struct I2s *i2s)
391 {
392         (void)i2s;
393         return (i2s_status & I2S_STATUS_END_TX);
394 }
395
396 static bool sam3_i2s_isRxFinish(struct I2s *i2s)
397 {
398         (void)i2s;
399         return (i2s_status & I2S_STATUS_END_RX);
400 }
401
402 static void sam3_i2s_txBuf(struct I2s *i2s, void *buf, size_t len)
403 {
404         (void)i2s;
405         i2s_status |= I2S_STATUS_SINGLE_TRASF;
406
407         dmac_setSources(I2S_DMAC_CH, (uint32_t)buf, (uint32_t)&SSC_THR);
408         dmac_configureDmac(I2S_DMAC_CH, len / I2S_WORD_BYTE_SIZE, I2S_TX_DMAC_CFG, I2S_TX_DMAC_CTRLA, I2S_TX_DMAC_CTRLB);
409         dmac_start(I2S_DMAC_CH);
410
411         SSC_CR = BV(SSC_TXEN);
412 }
413
414 static void sam3_i2s_rxBuf(struct I2s *i2s, void *buf, size_t len)
415 {
416         (void)i2s;
417
418         i2s_status |= I2S_STATUS_SINGLE_TRASF;
419
420         dmac_setSources(I2S_DMAC_CH, (uint32_t)&SSC_RHR, (uint32_t)buf);
421         dmac_configureDmac(I2S_DMAC_CH, len / I2S_WORD_BYTE_SIZE, I2S_RX_DMAC_CFG, I2S_RX_DMAC_CTRLA, I2S_RX_DMAC_CTRLB);
422         dmac_start(I2S_DMAC_CH);
423
424         SSC_CR = BV(SSC_TXEN) | BV(SSC_RXEN);
425 }
426
427 static int sam3_i2s_write(struct I2s *i2s, uint32_t sample)
428 {
429         (void)i2s;
430
431         SSC_CR = BV(SSC_TXEN);
432         while(!(SSC_SR & BV(SSC_TXRDY)))
433                 cpu_relax();
434
435         SSC_THR = sample;
436         return 0;
437 }
438
439 static uint32_t sam3_i2s_read(struct I2s *i2s)
440 {
441         (void)i2s;
442
443         SSC_CR = BV(SSC_RXEN);
444         while(!(SSC_SR & BV(SSC_RXRDY)))
445                 cpu_relax();
446
447         return SSC_RHR;
448 }
449
450
451 /* We divite for 2 because the min clock for i2s i MCLK/2 */
452 #define MCK_DIV     (CPU_FREQ / (CONFIG_SAMPLE_FREQ * CONFIG_WORD_BIT_SIZE * CONFIG_CHANNEL_NUM * 2))
453 #define DATALEN     ((CONFIG_WORD_BIT_SIZE - 1) & SSC_DATLEN_MASK)
454 #define DELAY       ((CONFIG_DELAY << SSC_STTDLY_SHIFT) & SSC_STTDLY_MASK)
455 #define PERIOD      ((CONFIG_PERIOD << (SSC_PERIOD_SHIFT)) & SSC_PERIOD_MASK)
456 #define DATNB       ((CONFIG_WORD_PER_FRAME << SSC_DATNB_SHIFT) & SSC_DATNB_MASK)
457 #define FSLEN       ((CONFIG_FRAME_SYNC_SIZE << SSC_FSLEN_SHIFT) & SSC_FSLEN_MASK)
458 #define EXTRA_FSLEN (CONFIG_EXTRA_FRAME_SYNC_SIZE << SSC_FSLEN_EXT)
459
460 void i2s_init(I2s *i2s, int channel)
461 {
462         (void)channel;
463         i2s->ctx.write = sam3_i2s_write;
464         i2s->ctx.tx_buf = sam3_i2s_txBuf;
465         i2s->ctx.tx_isFinish = sam3_i2s_isTxFinish;
466         i2s->ctx.tx_start = sam3_i2s_txStart;
467         i2s->ctx.tx_wait = sam3_i2s_txWait;
468         i2s->ctx.tx_stop = sam3_i2s_txStop;
469
470         i2s->ctx.read = sam3_i2s_read;
471         i2s->ctx.rx_buf = sam3_i2s_rxBuf;
472         i2s->ctx.rx_isFinish = sam3_i2s_isRxFinish;
473         i2s->ctx.rx_start = sam3_i2s_rxStart;
474         i2s->ctx.rx_wait = sam3_i2s_rxWait;
475         i2s->ctx.rx_stop = sam3_i2s_rxStop;
476
477         DB(i2s->ctx._type = I2S_SAM3X;)
478
479         I2S_STROBE_INIT();
480
481         PIOA_PDR = BV(SSC_TK) | BV(SSC_TF) | BV(SSC_TD);
482         PIO_PERIPH_SEL(PIOA_BASE, BV(SSC_TK) | BV(SSC_TF) | BV(SSC_TD), PIO_PERIPH_B);
483
484         PIOB_PDR = BV(SSC_RD) | BV(SSC_RF);
485         PIO_PERIPH_SEL(PIOB_BASE, BV(SSC_RD) | BV(SSC_RF), PIO_PERIPH_A);
486
487         /* clock the ssc */
488         pmc_periphEnable(SSC_ID);
489
490         /* reset device */
491         SSC_CR = BV(SSC_SWRST) | BV(SSC_TXDIS) | BV(SSC_RXDIS);
492
493         /* Set transmission clock */
494         SSC_CMR = MCK_DIV & SSC_DIV_MASK;
495         /* Set the transmission mode:
496          * - the clk is generate from master clock
497          * - clock only during transfer
498          * - transmit Clock Gating Selection none
499          * - DELAY cycle insert before starting transmission
500          * - generate frame sync each 2*(PERIOD + 1) tramit clock
501          * - Receive start on falling edge RF
502          */
503         SSC_TCMR = SSC_CKS_DIV | SSC_CKO_CONT | SSC_CKG_NONE | DELAY | PERIOD | SSC_START_FALL_F;
504         /* Set the transmission frame mode:
505          * - data len DATALEN + 1
506          * - word per frame DATNB + 1
507          * - frame sync len FSLEN + (FSLEN_EXT * 16) + 1
508          * - DELAY cycle insert before starting transmission
509          * - MSB
510          * - Frame sync output selection negative
511          */
512         SSC_TFMR = DATALEN | DATNB | FSLEN | EXTRA_FSLEN | BV(SSC_MSBF) | SSC_FSOS_NEGATIVE;
513
514
515         // Receiver should start on TX and take the clock from TK
516     SSC_RCMR = SSC_CKS_CLK | BV(SSC_CKI) | SSC_CKO_CONT | SSC_CKG_NONE | DELAY | PERIOD | SSC_START_TX;
517     SSC_RFMR = DATALEN | DATNB | FSLEN  | EXTRA_FSLEN | BV(SSC_MSBF) | SSC_FSOS_NEGATIVE;
518
519
520         SSC_IDR = 0xFFFFFFFF;
521
522         dmac_enableCh(I2S_DMAC_CH, i2s_dmac_irq);
523         event_initGeneric(&data_ready);
524 }