Use strobe macros. Clean up and reformat.
[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
59 #define I2S_DMAC_CH    3
60
61 struct I2sHardware
62 {
63         bool end;
64 };
65
66 struct I2sHardware i2s_hw;
67 static Event data_ready;
68
69 DmacDesc lli0;
70 DmacDesc lli1;
71 DmacDesc *curr;
72 DmacDesc *next;
73 DmacDesc *prev;
74
75 static int16_t *sample_buff;
76 static size_t next_idx = 0;
77 static size_t chunk_size = 0;
78 static size_t remaing_size = 0;
79 static size_t transfer_size = 0;
80 static bool single_transfer;
81
82 static void sam3_i2s_txStop(I2s *i2s)
83 {
84         (void)i2s;
85         SSC_CR = BV(SSC_TXDIS);
86         dmac_stop(I2S_DMAC_CH);
87
88         i2s->hw->end = true;
89         remaing_size = 0;
90
91         event_do(&data_ready);
92 }
93
94 static void sam3_i2s_txWait(I2s *i2s)
95 {
96         (void)i2s;
97         event_wait(&data_ready);
98 }
99
100 bool error = false;
101 uint32_t cfg;
102 uint32_t ctrla;
103 uint32_t ctrlb;
104
105 static void i2s_dmac_irq(uint32_t status)
106 {
107         I2S_STROBE_ON();
108         if (single_transfer)
109         {
110                 single_transfer = false;
111         }
112         else
113         {
114                 if (status & (BV(I2S_DMAC_CH) << DMAC_EBCIDR_ERR0))
115                 {
116                         error = true;
117                         // Disable to reset channel and clear fifo
118                         DMAC_CHDR = BV(I2S_DMAC_CH);
119                 }
120                 else
121                 {
122                         prev = curr;
123                         curr = next;
124                         next = prev;
125
126                         curr->src_addr = (uint32_t)&sample_buff[next_idx];
127                         curr->dst_addr = (uint32_t)&SSC_THR;
128                         curr->dsc_addr = (uint32_t)next;
129                         curr->ctrla    = ctrla | (chunk_size & 0xffff);
130                         curr->ctrlb    = ctrlb & ~BV(DMAC_CTRLB_IEN);
131
132                         remaing_size -= chunk_size;
133                         next_idx += chunk_size;
134
135                         if (remaing_size <= 0)
136                         {
137                                 remaing_size = transfer_size;
138                                 next_idx = 0;
139                         }
140                 }
141         }
142         event_do(&data_ready);
143         I2S_STROBE_OFF();
144 }
145
146 static void sam3_i2s_txStart(I2s *i2s, void *buf, size_t len, size_t slice_len)
147 {
148         ASSERT(buf);
149         ASSERT(len >= slice_len);
150         ASSERT(!(len % slice_len));
151
152         i2s->hw->end = false;
153         single_transfer = false;
154
155         sample_buff = (int16_t *)buf;
156         next_idx = 0;
157         chunk_size = slice_len / 2;
158         remaing_size = len / 2;
159         transfer_size = len / 2;
160
161
162         //Confing DMAC
163         DMAC_CHDR = BV(I2S_DMAC_CH);
164         reg32_t reg = DMAC_EBCISR;
165
166         LOG_INFO("Start streaming [%08lx]\n", reg);
167
168         cfg = BV(DMAC_CFG_DST_H2SEL) | BV(DMAC_CFG_SOD) |
169                 ((3 << DMAC_CFG_DST_PER_SHIFT) & DMAC_CFG_DST_PER_MASK) | (3 & DMAC_CFG_SRC_PER_MASK);
170         ctrla = DMAC_CTRLA_SRC_WIDTH_HALF_WORD | DMAC_CTRLA_DST_WIDTH_HALF_WORD;
171         ctrlb = DMAC_CTRLB_FC_MEM2PER_DMA_FC | DMAC_CTRLB_DST_INCR_FIXED | DMAC_CTRLB_SRC_INCR_INCREMENTING;
172
173         prev = &lli0;
174         curr = &lli0;
175         next = &lli1;
176
177         i2s->ctx.tx_callback(i2s, &sample_buff[0], chunk_size * 2);
178
179         lli0.src_addr = (uint32_t)&sample_buff[0];
180         lli0.dst_addr = (uint32_t)&SSC_THR;
181         lli0.dsc_addr = (uint32_t)next;
182         lli0.ctrla    = ctrla | (chunk_size & 0xffff);
183         lli0.ctrlb    = ctrlb & ~BV(DMAC_CTRLB_IEN);
184
185         remaing_size -= chunk_size;
186         next_idx += chunk_size;
187
188         if (chunk_size <= remaing_size)
189         {
190                 i2s->ctx.tx_callback(i2s, &sample_buff[next_idx], chunk_size * 2);
191
192                 prev = curr;
193                 curr = next;
194                 next = prev;
195
196                 lli1.src_addr = (uint32_t)&sample_buff[next_idx];
197                 lli1.dst_addr = (uint32_t)&SSC_THR;
198                 lli1.dsc_addr = (uint32_t)next;
199                 lli1.ctrla    = ctrla | (chunk_size & 0xffff);
200                 lli1.ctrlb    = ctrlb & ~BV(DMAC_CTRLB_IEN);
201
202                 remaing_size -= chunk_size;
203                 next_idx += chunk_size;
204         }
205
206         dmac_configureDmaCfgLLI(I2S_DMAC_CH, &lli0, cfg);
207
208         if (dmac_start(I2S_DMAC_CH) < 0)
209         {
210                 LOG_ERR("DMAC start[%x]\n", dmac_error(I2S_DMAC_CH));
211                 return;
212         }
213
214         error = false;
215         SSC_CR = BV(SSC_TXEN);
216         PIOA_CODR = BV(13);
217
218         while (1)
219         {
220                 event_wait(&data_ready);
221                 if (error)
222                 {
223                         LOG_ERR("Errow while streaming.\n");
224                         break;
225                 }
226
227                 if (i2s->hw->end)
228                         break;
229
230                 i2s->ctx.tx_callback(i2s, &sample_buff[next_idx], chunk_size * 2);
231                 cpu_relax();
232         }
233 }
234
235 static void sam3_i2s_rxStop(I2s *i2s)
236 {
237         (void)i2s;
238         SSC_CR = BV(SSC_TXDIS);
239 }
240
241 static void sam3_i2s_rxWait(I2s *i2s)
242 {
243         (void)i2s;
244 }
245
246 static void sam3_i2s_rxStart(I2s *i2s, void *buf, size_t len, size_t slice_len)
247 {
248         (void)i2s;
249         (void)buf;
250         (void)len;
251         (void)slice_len;
252 }
253
254
255 static bool sam3_i2s_isTxFinish(struct I2s *i2s)
256 {
257         (void)i2s;
258         return i2s->hw->end;
259 }
260
261 static bool sam3_i2s_isRxFinish(struct I2s *i2s)
262 {
263         (void)i2s;
264         return 0;
265 }
266
267 static void sam3_i2s_txBuf(struct I2s *i2s, void *buf, size_t len)
268 {
269         (void)i2s;
270
271         single_transfer = true;
272
273         uint32_t cfg = BV(DMAC_CFG_DST_H2SEL) |
274                                 ((3 << DMAC_CFG_DST_PER_SHIFT) & DMAC_CFG_DST_PER_MASK) | (3 & DMAC_CFG_SRC_PER_MASK);
275         uint32_t ctrla = DMAC_CTRLA_SRC_WIDTH_HALF_WORD | DMAC_CTRLA_DST_WIDTH_HALF_WORD;
276         uint32_t ctrlb = BV(DMAC_CTRLB_SRC_DSCR) | BV(DMAC_CTRLB_DST_DSCR) |
277                                 DMAC_CTRLB_FC_MEM2PER_DMA_FC |
278                                 DMAC_CTRLB_DST_INCR_FIXED | DMAC_CTRLB_SRC_INCR_INCREMENTING;
279
280         dmac_setSources(I2S_DMAC_CH, (uint32_t)buf, (uint32_t)&SSC_THR);
281         dmac_configureDmac(I2S_DMAC_CH, len, cfg, ctrla, ctrlb);
282         dmac_start(I2S_DMAC_CH);
283
284         SSC_CR = BV(SSC_TXEN);
285 }
286
287 static void sam3_i2s_rxBuf(struct I2s *i2s, void *buf, size_t len)
288 {
289         (void)i2s;
290
291         uint32_t cfg = BV(DMAC_CFG_SRC_H2SEL) |
292                                 ((4 << DMAC_CFG_DST_PER_SHIFT) & DMAC_CFG_DST_PER_MASK) | (4 & DMAC_CFG_SRC_PER_MASK);
293         uint32_t ctrla = DMAC_CTRLA_SRC_WIDTH_HALF_WORD | DMAC_CTRLA_DST_WIDTH_HALF_WORD;
294         uint32_t ctrlb = BV(DMAC_CTRLB_SRC_DSCR) | BV(DMAC_CTRLB_DST_DSCR) |
295                                                 DMAC_CTRLB_FC_PER2MEM_DMA_FC |
296                                                 DMAC_CTRLB_DST_INCR_INCREMENTING | DMAC_CTRLB_SRC_INCR_FIXED;
297
298         dmac_setSources(I2S_DMAC_CH, (uint32_t)&SSC_RHR, (uint32_t)buf);
299         dmac_configureDmac(I2S_DMAC_CH, len / 2, cfg, ctrla, ctrlb);
300         dmac_start(I2S_DMAC_CH);
301
302         SSC_CR = BV(SSC_RXEN);
303 }
304
305 static int sam3_i2s_write(struct I2s *i2s, uint32_t sample)
306 {
307         (void)i2s;
308
309         SSC_CR = BV(SSC_TXEN);
310         while(!(SSC_SR & BV(SSC_TXRDY)))
311                 cpu_relax();
312
313         SSC_THR = sample;
314         return 0;
315 }
316
317 static uint32_t sam3_i2s_read(struct I2s *i2s)
318 {
319         (void)i2s;
320
321         SSC_CR = BV(SSC_RXEN);
322         while(!(SSC_SR & BV(SSC_RXRDY)))
323                 cpu_relax();
324
325         return SSC_RHR;
326 }
327
328
329 /* We divite for 2 because the min clock for i2s i MCLK/2 */
330 #define MCK_DIV     (CPU_FREQ / (CONFIG_SAMPLE_FREQ * CONFIG_WORD_BIT_SIZE * CONFIG_CHANNEL_NUM * 2))
331 #define DATALEN     ((CONFIG_WORD_BIT_SIZE - 1) & SSC_DATLEN_MASK)
332 #define DELAY       ((CONFIG_DELAY << SSC_STTDLY_SHIFT) & SSC_STTDLY_MASK)
333 #define PERIOD      ((CONFIG_PERIOD << (SSC_PERIOD_SHIFT)) & SSC_PERIOD_MASK)
334 #define DATNB       ((CONFIG_WORD_PER_FRAME << SSC_DATNB_SHIFT) & SSC_DATNB_MASK)
335 #define FSLEN       ((CONFIG_FRAME_SYNC_SIZE << SSC_FSLEN_SHIFT) & SSC_FSLEN_MASK)
336 #define EXTRA_FSLEN (CONFIG_EXTRA_FRAME_SYNC_SIZE << SSC_FSLEN_EXT)
337
338 void i2s_init(I2s *i2s, int channel)
339 {
340         (void)channel;
341         i2s->ctx.write = sam3_i2s_write;
342         i2s->ctx.tx_buf = sam3_i2s_txBuf;
343         i2s->ctx.tx_isFinish = sam3_i2s_isTxFinish;
344         i2s->ctx.tx_start = sam3_i2s_txStart;
345         i2s->ctx.tx_wait = sam3_i2s_txWait;
346         i2s->ctx.tx_stop = sam3_i2s_txStop;
347
348         i2s->ctx.read = sam3_i2s_read;
349         i2s->ctx.rx_buf = sam3_i2s_rxBuf;
350         i2s->ctx.rx_isFinish = sam3_i2s_isRxFinish;
351         i2s->ctx.rx_start = sam3_i2s_rxStart;
352         i2s->ctx.rx_wait = sam3_i2s_rxWait;
353         i2s->ctx.rx_stop = sam3_i2s_rxStop;
354
355         DB(i2s->ctx._type = I2S_SAM3X;)
356         i2s->hw = &i2s_hw;
357
358         I2S_STROBE_INIT();
359
360         PIOA_PDR = BV(SSC_TK) | BV(SSC_TF) | BV(SSC_TD);
361         PIO_PERIPH_SEL(PIOA_BASE, BV(SSC_TK) | BV(SSC_TF) | BV(SSC_TD), PIO_PERIPH_B);
362         PIOB_PDR = BV(SSC_RD) | BV(SSC_RF);
363         PIO_PERIPH_SEL(PIOB_BASE, BV(SSC_RD) | BV(SSC_RF), PIO_PERIPH_A);
364
365         /* clock the ssc */
366         pmc_periphEnable(SSC_ID);
367
368         /* reset device */
369         SSC_CR = BV(SSC_SWRST) | BV(SSC_TXDIS) | BV(SSC_RXDIS);
370
371         /* Set transmission clock */
372         SSC_CMR = MCK_DIV & SSC_DIV_MASK;
373         /* Set the transmission mode:
374          * - the clk is generate from master clock
375          * - clock only during transfer
376          * - transmit Clock Gating Selection none
377          * - DELAY cycle insert before starting transmission
378          * - generate frame sync each 2*(PERIOD + 1) tramit clock
379          * - Receive start on falling edge RF
380          */
381         SSC_TCMR = SSC_CKS_DIV | SSC_CKO_CONT | SSC_CKG_NONE | DELAY | PERIOD | SSC_START_FALL_F;
382         /* Set the transmission frame mode:
383          * - data len DATALEN + 1
384          * - word per frame DATNB + 1
385          * - frame sync len FSLEN + (FSLEN_EXT * 16) + 1
386          * - DELAY cycle insert before starting transmission
387          * - MSB
388          * - Frame sync output selection negative
389          */
390         SSC_TFMR = DATALEN | DATNB | FSLEN | EXTRA_FSLEN | BV(SSC_MSBF) | SSC_FSOS_NEGATIVE;
391
392
393         // Receiver should start on TX and take the clock from TK
394     SSC_RCMR = SSC_CKS_CLK | BV(SSC_CKI) | SSC_CKO_CONT | SSC_CKG_NONE | DELAY | PERIOD | SSC_START_TX;
395     SSC_RFMR = DATALEN | DATNB | FSLEN  | EXTRA_FSLEN | BV(SSC_MSBF) | SSC_FSOS_NEGATIVE;
396
397
398         SSC_IDR = 0xFFFFFFFF;
399
400         dmac_enableCh(I2S_DMAC_CH, i2s_dmac_irq);
401         event_initGeneric(&data_ready);
402 }