Reformat.
[bertos.git] / bertos / drv / i2s.h
index 2623702c4e17fe165c804e20a694bc436b0464f0..8758cb0080cb7e2a18e0340743495214603c1893 100644 (file)
  * invalidate any other reasons why the executable file might be covered by
  * the GNU General Public License.
  *
- * Copyright 2009 Develer S.r.l. (http://www.develer.com/)
+ * Copyright 2011 Develer S.r.l. (http://www.develer.com/)
  *
  * -->
  *
- * \brief I2S driver functions.
+ * \defgroup i2s Generic I2S driver
+ * \ingroup drivers
+ * \{
+ * \brief
  *
- * This driver uses a double buffering technique to keep i2s bus busy. First fill in the two buffers
- * using i2s_getBuffer(), then start audio playing with i2s_start(). Then call i2s_getFreeBuffer()
- * until you have finished your samples. The reproduction will automatically stop if you don't
- * call i2s_getFreeBuffer() frequently enough.
+ * <b>Configuration file</b>: cfg_i2s.h
  *
- * Example:
- * \code
- * // fill in the buffers before start
- * buf = i2s_getBuffer(I2S_FIRST_BUF);
- * // ...
- * buf = i2s_getBuffer(I2S_SECOND_BUF);
- * // ...
- * // here the driver will play only the first two buffers...
- * i2s_start();
- * // ...call getFreeBuffer() to continue playing.
- * while (!(buf = i2s_getFreeBuffer()))
- *     ;
- * // now fill the buffer again
- * \endcode
- *
- * \version $Id$
- * \author Luca Ottaviano <lottaviano@develer.com>
+ * \author Daniele Basile <asterix@develer.com>
  *
  * $WIZ$ module_name = "i2s"
  * $WIZ$ module_configuration = "bertos/cfg/cfg_i2s.h"
- * $WIZ$ module_supports = "not atmega103 and not atmega168 and not atmega8"
+ * $WIZ$ module_supports = "not all"
  */
 
-#ifndef I2S_H
-#define I2S_H
 
-#include "cfg/cfg_i2s.h"
+#ifndef DRV_I2S_H
+#define DRV_I2S_H
+
+#warning __FILTER_NEXT_WARNING__
+#warning This API is ALPHA! we could change it..
 
 #include <cfg/compiler.h>
+#include <cfg/debug.h>
 #include <cfg/macros.h>
-#include <io/arm.h>
 
-/**
- * First buffer.
- */
-#define I2S_FIRST_BUF  0
-/**
- * Second buffer.
- */
-#define I2S_SECOND_BUF 1
+#include <cpu/attr.h>
 
-/**
- * Initializes the module and sets current buffer to I2S_FIRST_BUF.
- */
-void i2s_init(void);
+#include CPU_HEADER(i2s)
 
-/**
- * Returns one of the two buffers or NULL if none is available.
- *
- * You can't call this function if you have already started the player.
- * \param buf_num The number of the buffer, ie I2S_FIRST_BUF or I2S_SECOND_BUF.
- * \return A pointer to the buffer if the buffer is available (not full), 0 on errors
- */
-uint8_t *i2s_getBuffer(unsigned buf_num);
+struct I2sContext;
+struct I2s;
 
-/**
- * Returns a buffer that will be played after the current one.
- *
- * You should fill it faster than your reproduction time. You can't call this function
- * if the player is not running
- * \return The next buffer to be played, 0 if both are busy.
- */
-uint8_t *i2s_getFreeBuffer(void);
+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);
 
-/**
- * Starts playing from I2S_FIRST_BUFFER.
+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.
  *
- * You must have filled both buffers before calling this function. Does nothing if already playing.
- * \return false on errors, true otherwise.
+ * Useful for kernel-less applications.
  */
-bool i2s_start(void);
+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_dmaTxWait(I2s *i2s)
+{
+       ASSERT(i2s->ctx.tx_wait);
+       i2s->ctx.tx_wait(i2s);
+}
+
+
+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.tx_callback = callback;
+       i2s->ctx.tx_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 bool i2s_isPlaying(void)
+INLINE void i2s_dmaStartRxStreaming(I2s *i2s, void *buf, size_t len, size_t slice_len, i2s_dma_callback_t callback)
 {
-       return !(SSC_SR & BV(SSC_TXEMPTY));
+       ASSERT(i2s->ctx.rx_start);
+       ASSERT(len % slice_len == 0);
+       ASSERT(callback);
+
+       i2s->ctx.rx_callback = callback;
+       i2s->ctx.rx_slice_len = slice_len;
+       i2s->ctx.rx_start(i2s, buf, len, slice_len);
 }
 
-#endif /* I2S_H */
+INLINE void i2s_dmaRxStop(I2s *i2s)
+{
+       ASSERT(i2s->ctx.rx_stop);
+       i2s->ctx.rx_stop(i2s);
+}
+
+void i2s_init(I2s *i2s, int channel);
+
+/** \} */ //defgroup i2s
+#endif /* DRV_I2S_H */