imx233/fuze+: implement pcm out and audio codec, update SOURCES

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@30800 a1c6a512-1295-4272-9138-f99709370657
diff --git a/firmware/SOURCES b/firmware/SOURCES
index 739f8e6..b729a9b 100644
--- a/firmware/SOURCES
+++ b/firmware/SOURCES
@@ -522,8 +522,10 @@
 #endif
 #ifndef BOOTLOADER
 #ifdef HAVE_IMX233_CODEC
+target/arm/imx233/audioout-imx233.c
+target/arm/imx233/audioin-imx233.c
 target/arm/imx233/pcm-imx233.c
-target/arm/imx233/audiohw-imx233.c
+drivers/audio/imx233-codec.c
 #endif
 target/arm/imx233/timer-imx233.c
 #endif
diff --git a/firmware/drivers/audio/imx233-codec.c b/firmware/drivers/audio/imx233-codec.c
index 769216a..d99a4d0 100644
--- a/firmware/drivers/audio/imx233-codec.c
+++ b/firmware/drivers/audio/imx233-codec.c
@@ -22,34 +22,61 @@
 #include "system.h"
 #include "audiohw.h"
 #include "audio.h"
+#include "audioout-imx233.h"
+#include "audioin-imx233.h"
 
-/* TO FILL */
 const struct sound_settings_info audiohw_settings[] =
 {
-    [SOUND_VOLUME]        = {"dB", 0,  1, -74,   6, -25},
+    /* i.MX233 has half dB steps */
+    [SOUND_VOLUME]        = {"dB", 0,  5, VOLUME_MIN / 10,   VOLUME_MAX / 10, -25},
+    /* HAVE_SW_TONE_CONTROLS */
+    [SOUND_BASS]          = {"dB", 0,  1, -24,  24,   0},
+    [SOUND_TREBLE]        = {"dB", 0,  1, -24,  24,   0},
     [SOUND_BALANCE]       = {"%",  0,  1,-100, 100,   0},
     [SOUND_CHANNELS]      = {"",   0,  1,   0,   5,   0},
     [SOUND_STEREO_WIDTH]  = {"%",  0,  5,   0, 250, 100},
+#ifdef HAVE_RECORDING
     [SOUND_LEFT_GAIN]     = {"dB", 1,  1,   0,  31,  23},
     [SOUND_RIGHT_GAIN]    = {"dB", 1,  1,   0,  31,  23},
     [SOUND_MIC_GAIN]      = {"dB", 1,  1,   0,   1,   0},
+#endif
     [SOUND_DEPTH_3D]      = {"%",   0,  1,  0,  15,   0},
 };
 
-void audiohw_init(void)
+int tenthdb2master(int tdb)
 {
+    /* Just go from tenth of dB to half to dB */
+    return tdb / 5;
 }
 
 void audiohw_preinit(void)
 {
+    imx233_audioout_preinit();
+    imx233_audioin_preinit();
 }
 
 void audiohw_postinit(void)
 {
+    imx233_audioout_postinit();
+    imx233_audioin_postinit();
 }
 
 void audiohw_close(void)
 {
+    imx233_audioout_close();
+    imx233_audioin_close();
+}
+
+void audiohw_set_headphone_vol(int vol_l, int vol_r)
+{
+    /* Use playback volume if <0 and headphone volume if >0 */
+    imx233_audioout_set_dac_vol(MIN(0, vol_l), MIN(0, vol_r));
+    imx233_audioout_set_hp_vol(MAX(0, vol_l), MAX(0, vol_r));
+}
+
+void audiohw_set_frequency(int fsel)
+{
+    imx233_audioout_set_freq(fsel);
 }
 
 void audiohw_set_recvol(int left, int right, int type)
diff --git a/firmware/target/arm/imx233/pcm-imx233.c b/firmware/target/arm/imx233/pcm-imx233.c
index 6dd678f..fa13f99 100644
--- a/firmware/target/arm/imx233/pcm-imx233.c
+++ b/firmware/target/arm/imx233/pcm-imx233.c
@@ -22,32 +22,79 @@
 #include "config.h"
 #include "audiohw.h"
 #include "pcm.h"
-#include "audioin-imx233.h"
+#include "dma-imx233.h"
+#include "pcm-internal.h"
 #include "audioout-imx233.h"
 
+static int locked = 0;
+static struct apb_dma_command_t dac_dma;
+static bool pcm_freezed = false;
+
+/**
+ * WARNING !
+ * Never reset the dma channel, otherwise it will halt the DAC for some reason
+ * */
+
+static void play(const void *addr, size_t size)
+{
+    dac_dma.next = NULL;
+    dac_dma.buffer = (void *)addr;
+    dac_dma.cmd = HW_APB_CHx_CMD__COMMAND__READ |
+        HW_APB_CHx_CMD__IRQONCMPLT |
+        HW_APB_CHx_CMD__SEMAPHORE |
+        size << HW_APB_CHx_CMD__XFER_COUNT_BP;
+    /* dma subsystem will make sure cached stuff is written to memory */
+    imx233_dma_start_command(APB_AUDIO_DAC, &dac_dma);
+}
+
+void INT_DAC_DMA(void)
+{
+    void *start;
+    size_t size;
+
+    pcm_play_get_more_callback(&start, &size);
+
+    if(size != 0)
+    {
+        play(start, size);
+        pcm_play_dma_started_callback();
+    }
+
+    imx233_dma_clear_channel_interrupt(APB_AUDIO_DAC);
+}
+
+void INT_DAC_ERROR(void)
+{
+}
+
 void pcm_play_lock(void)
 {
+    if(locked++ == 0)
+        imx233_dma_enable_channel_interrupt(APB_AUDIO_DAC, false);
 }
 
 void pcm_play_unlock(void)
 {
+    if(--locked == 0)
+        imx233_dma_enable_channel_interrupt(APB_AUDIO_DAC, true);
 }
 
 void pcm_play_dma_stop(void)
 {
+    
 }
 
 void pcm_play_dma_start(const void *addr, size_t size)
 {
     pcm_play_dma_stop();
 
-    (void) addr;
-    (void) size;
+    play(addr, size);
 }
 
 void pcm_play_dma_pause(bool pause)
 {
-    (void) pause;
+    imx233_dma_freeze_channel(APB_AUDIO_DAC, pause);
+    pcm_freezed = pause;
 }
 
 void pcm_play_dma_init(void)
@@ -58,22 +105,31 @@
 void pcm_play_dma_postinit(void)
 {
     audiohw_postinit();
+    imx233_enable_interrupt(INT_SRC_DAC_DMA, true);
+    imx233_enable_interrupt(INT_SRC_DAC_ERROR, true);
+    imx233_dma_enable_channel_interrupt(APB_AUDIO_DAC, true);
 }
 
 void pcm_dma_apply_settings(void)
 {
-    return;
+    audiohw_set_frequency(pcm_fsel);
 }
 
 size_t pcm_get_bytes_waiting(void)
 {
-    return 0;
+    struct imx233_dma_info_t info = imx233_dma_get_info(APB_AUDIO_DAC, DMA_INFO_AHB_BYTES);
+    return info.ahb_bytes;
 }
 
 const void *pcm_play_dma_get_peak_buffer(int *count)
 {
-    (void) count;
-    return NULL;
+    if(!pcm_freezed)
+        imx233_dma_freeze_channel(APB_AUDIO_DAC, true);
+    struct imx233_dma_info_t info = imx233_dma_get_info(APB_AUDIO_DAC, DMA_INFO_AHB_BYTES | DMA_INFO_BAR);
+    if(!pcm_freezed)
+        imx233_dma_freeze_channel(APB_AUDIO_DAC, false);
+    *count = info.ahb_bytes;
+    return (void *)info.bar;
 }
 
 void pcm_rec_lock(void)
diff --git a/firmware/target/arm/imx233/sansa-fuzeplus/audio-fuzeplus.c b/firmware/target/arm/imx233/sansa-fuzeplus/audio-fuzeplus.c
index fa4294f..1aac9e4 100644
--- a/firmware/target/arm/imx233/sansa-fuzeplus/audio-fuzeplus.c
+++ b/firmware/target/arm/imx233/sansa-fuzeplus/audio-fuzeplus.c
@@ -22,6 +22,8 @@
 #include "system.h"
 #include "audiohw.h"
 #include "audio.h"
+#include "audioout-imx233.h"
+#include "audioin-imx233.h"
 
 void audio_input_mux(int source, unsigned flags)
 {