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