+#include <cfg/debug.h>
+#include <cfg/macros.h>
+
+#include <cpu/attr.h>
+
+#include CPU_HEADER(i2s)
+
+struct I2sContext;
+struct I2s;
+
+typedef int (*i2s_write_t) (struct I2s *i2s, uint32_t sample);
+typedef uint32_t (*i2s_read_t) (struct I2s *i2s);
+typedef void (*i2s_dma_tx_buf_t) (struct I2s *i2s, void *buf, size_t len);
+typedef void (*i2s_dma_rx_buf_t) (struct I2s *i2s, void *buf, size_t len);
+typedef bool (*i2s_dma_tx_is_finished_t) (struct I2s *i2s);
+typedef bool (*i2s_dma_rx_is_finished_t) (struct I2s *i2s);
+typedef void (*i2s_dma_callback_t) (struct I2s *i2s, void *_buf, size_t len);
+typedef void (*i2s_dma_start_streaming_t) (struct I2s *i2s, void *buf, size_t len, size_t slice_len);
+typedef void (*i2s_dma_wait_t) (struct I2s *i2s);
+typedef void (*i2s_dma_stop_t) (struct I2s *i2s);
+
+typedef struct I2sContext
+{
+ i2s_write_t write;
+ i2s_dma_tx_buf_t tx_buf;
+ i2s_dma_tx_is_finished_t tx_isFinish;
+ i2s_dma_callback_t tx_callback;
+ i2s_dma_start_streaming_t tx_start;
+ i2s_dma_wait_t tx_wait;
+ i2s_dma_stop_t tx_stop;
+ size_t tx_slice_len;
+
+ i2s_read_t read;
+ i2s_dma_rx_buf_t rx_buf;
+ i2s_dma_rx_is_finished_t rx_isFinish;
+ i2s_dma_callback_t rx_callback;
+ i2s_dma_start_streaming_t rx_start;
+ i2s_dma_wait_t rx_wait;
+ i2s_dma_stop_t rx_stop;
+ size_t rx_slice_len;
+
+ DB(id_t _type);
+
+} I2sContext;
+
+typedef struct I2s
+{
+ I2sContext ctx;
+ struct I2sHardware *hw;
+} I2s;
+
+INLINE int i2s_write(I2s *i2s, uint32_t sample)
+{
+ ASSERT(i2s->ctx.write);
+ return i2s->ctx.write(i2s, sample);
+}
+
+
+INLINE uint32_t i2s_read(I2s *i2s)
+{
+ ASSERT(i2s->ctx.read);
+ return i2s->ctx.read(i2s);
+}
+
+/*
+ * Check if a dma transfer is finished.
+ *
+ * Useful for kernel-less applications.
+ */
+INLINE bool i2s_dmaTxIsFinished(I2s *i2s)
+{
+ ASSERT(i2s->ctx.tx_isFinish);
+ return i2s->ctx.tx_isFinish(i2s);
+}
+
+INLINE bool i2s_dmaRxIsFinished(I2s *i2s)
+{
+ ASSERT(i2s->ctx.rx_isFinish);
+ return i2s->ctx.rx_isFinish(i2s);
+}
+
+INLINE void i2s_dmaTxBuffer(I2s *i2s, void *buf, size_t len)
+{
+ ASSERT(i2s->ctx.tx_buf);
+ i2s->ctx.tx_buf(i2s, buf, len);
+}
+
+INLINE void i2s_dmaRxBuffer(I2s *i2s, void *buf, size_t len)
+{
+ ASSERT(i2s->ctx.rx_buf);
+ i2s->ctx.rx_buf(i2s, buf, len);
+}
+
+
+INLINE void i2s_dmaStartTxStreaming(I2s *i2s, void *buf, size_t len, size_t slice_len, i2s_dma_callback_t callback)
+{
+ ASSERT(i2s->ctx.tx_start);
+ ASSERT(len % slice_len == 0);
+ ASSERT(callback);
+
+ i2s->ctx.rx_callback = callback;
+ i2s->ctx.rx_slice_len = slice_len;
+ i2s->ctx.tx_start(i2s, buf, len, slice_len);
+}
+
+INLINE void i2s_dmaTxStop(I2s *i2s)
+{
+ ASSERT(i2s->ctx.tx_stop);
+ i2s->ctx.tx_stop(i2s);
+}
+
+
+INLINE void i2s_dmaStartRxStreaming(I2s *i2s, void *buf, size_t len, size_t slice_len, i2s_dma_callback_t callback)
+{
+ ASSERT(i2s->ctx.rx_start);
+ ASSERT(len % slice_len == 0);
+ ASSERT(callback);