uda1380: Added bass/treble and recording functions


git-svn-id: svn://svn.rockbox.org/rockbox/trunk@6729 a1c6a512-1295-4272-9138-f99709370657
diff --git a/firmware/drivers/uda1380.c b/firmware/drivers/uda1380.c
index 4b63ccd..4eb04d1 100644
--- a/firmware/drivers/uda1380.c
+++ b/firmware/drivers/uda1380.c
@@ -39,27 +39,28 @@
 int uda1380_write_reg(unsigned char reg, unsigned short value);
 unsigned short uda1380_regs[0x30];
 
-/* Definition of a good (?) configuration to start with */
-/* Not enabling ADC for now.. */
+/* Definition of a playback configuration to start with */
 
 #define NUM_DEFAULT_REGS 13
-unsigned short uda1380_defaults[2*NUM_DEFAULT_REGS] = 
+unsigned short uda1380_defaults[2*NUM_DEFAULT_REGS] =
 {
-        REG_0,        EN_DAC | EN_INT | EN_DEC | SYSCLK_256FS | WSPLL_25_50,
-        REG_I2S,      I2S_IFMT_IIS,
-        REG_PWR,      PON_PLL | PON_DAC | PON_BIAS,   /* PON_HP is enabled later */
-        REG_AMIX,     AMIX_RIGHT(0x10) | AMIX_LEFT(0x10), /* 00=max, 3f=mute */
-        REG_MASTER_VOL, MASTER_VOL_LEFT(0x20) | MASTER_VOL_RIGHT(0x20), /* 00=max, ff=mute */
-        REG_MIX_VOL,    MIX_VOL_CHANNEL_1(0) | MIX_VOL_CHANNEL_2(0xff), /* 00=max, ff=mute */
-        REG_EQ,         0,
-        REG_MUTE,       MUTE_MASTER, /* Mute everything to start with */ 
-        REG_MIX_CTL,    0,
-        REG_DEC_VOL,    0,
-        REG_PGA,        MUTE_ADC,
-        REG_ADC,        SKIP_DCFIL,
-        REG_AGC,        0
+   REG_0,          EN_DAC | EN_INT | EN_DEC | SYSCLK_256FS | WSPLL_25_50,
+   REG_I2S,        I2S_IFMT_IIS,
+   REG_PWR,        PON_PLL | PON_DAC | PON_BIAS,                   /* PON_HP is enabled later */
+   REG_AMIX,       AMIX_RIGHT(0x3f) | AMIX_LEFT(0x3f),             /* 00=max, 3f=mute */
+   REG_MASTER_VOL, MASTER_VOL_LEFT(0x20) | MASTER_VOL_RIGHT(0x20), /* 00=max, ff=mute */
+   REG_MIX_VOL,    MIX_VOL_CH_1(0) | MIX_VOL_CH_2(0xff),           /* 00=max, ff=mute */
+   REG_EQ,         EQ_MODE_MAX,                                    /* Bass and tremble = 0 dB */
+   REG_MUTE,       MUTE_MASTER,                                    /* Mute everything to start with */ 
+   REG_MIX_CTL,    0,
+   REG_DEC_VOL,    0,
+   REG_PGA,        MUTE_ADC,
+   REG_ADC,        SKIP_DCFIL,
+   REG_AGC,        0
 };
 
+  
+
 /* Returns 0 if register was written or -1 if write failed */
 int uda1380_write_reg(unsigned char reg, unsigned short value)
 {
@@ -93,6 +94,22 @@
                              MASTER_VOL_LEFT(vol) | MASTER_VOL_RIGHT(vol));
 }
 
+/** 
+ * Sets the bass value (0-15)
+ */
+void uda1380_set_bass(int value)
+{
+    uda1380_write_reg(REG_EQ, (uda1380_regs[REG_EQ] & ~BASS_MASK) | BASSL(value) | BASSR(value));
+}
+
+/**
+ * Sets the treble value (0-3)
+ */
+void uda1380_set_treble(int value)
+{
+    uda1380_write_reg(REG_EQ, (uda1380_regs[REG_EQ] & ~TREBLE_MASK) | TREBLEL(value) | TREBLER(value));
+}
+
 /**
  * Mute (mute=1) or enable sound (mute=0)
  *
@@ -163,3 +180,81 @@
     uda1380_write_reg(REG_PWR, 0);
     uda1380_write_reg(REG_0, 0);    /* Disable codec    */
 }
+
+/**
+ * Calling this function enables the UDA1380 to send
+ * sound samples over the I2S bus, which is connected
+ * to the processor's IIS1 interface. 
+ *
+ * source_mic: true=record from microphone, false=record from line-in
+ */
+void uda1380_enable_recording(bool source_mic)
+{
+   uda1380_write_reg(REG_0, uda1380_regs[REG_0] | EN_ADC);
+
+    if (source_mic)
+    {
+        uda1380_write_reg(REG_PWR, uda1380_regs[REG_PWR] | PON_LNA | PON_ADCL);
+        uda1380_write_reg(REG_ADC, (uda1380_regs[REG_ADC] & VGA_GAIN_MASK) | SEL_LNA | SEL_MIC | EN_DCFIL);   /* VGA_GAIN: 0=0 dB, F=30dB */
+        uda1380_write_reg(REG_PGA, 0);
+    } else
+    {
+        uda1380_write_reg(REG_PWR, uda1380_regs[REG_PWR] | PON_PGAL | PON_ADCL | PON_PGAR | PON_ADCR);
+        uda1380_write_reg(REG_ADC, EN_DCFIL);
+        uda1380_write_reg(REG_PGA, (uda1380_regs[REG_PGA] & PGA_GAIN_MASK) | PGA_GAINL(0) | PGA_GAINR(0)); /* PGA_GAIN: 0=0 dB, F=24dB */
+    }
+
+    uda1380_write_reg(REG_I2S,     uda1380_regs[REG_I2S] | I2S_MODE_MASTER);
+    uda1380_write_reg(REG_MIX_CTL, MIX_MODE(3));   /* Not sure which mode is the best one.. */
+
+}
+
+/** 
+ * Stop sending samples on the I2S bus 
+ */
+void uda1380_disable_recording(void)
+{
+    uda1380_write_reg(REG_PGA, MUTE_ADC);
+    sleep(HZ/8);
+    
+    uda1380_write_reg(REG_I2S, I2S_IFMT_IIS);
+    uda1380_write_reg(REG_PWR, uda1380_regs[REG_PWR] & ~(PON_LNA | PON_ADCL | PON_ADCR | PON_PGAL | PON_PGAR));
+    uda1380_write_reg(REG_0,   uda1380_regs[REG_0] & ~EN_ADC);
+    uda1380_write_reg(REG_ADC, SKIP_DCFIL);
+}
+
+/**
+ * Set recording gain and volume
+ * 
+ * mic_gain    : range    0 .. 15 ->   0 .. 30 dB gain
+ * linein_gain : range    0 .. 15 ->   0 .. 24 dB gain
+ * 
+ * adc_volume  : range -127 .. 48 -> -63 .. 24 dB gain
+ *   note that 0 -> 0 dB gain..
+ */
+void uda1380_set_recvol(int mic_gain, int linein_gain, int adc_volume)
+{
+    uda1380_write_reg(REG_DEC_VOL, DEC_VOLL(adc_volume) | DEC_VOLR(adc_volume));
+    uda1380_write_reg(REG_PGA, (uda1380_regs[REG_PGA] & ~PGA_GAIN_MASK) | PGA_GAINL(linein_gain) | PGA_GAINR(linein_gain));
+    uda1380_write_reg(REG_ADC, (uda1380_regs[REG_ADC] & ~VGA_GAIN_MASK) | VGA_GAIN(mic_gain));
+}
+
+
+/** 
+ * Enable or disable recording monitor (so one can listen to the recording)
+ * 
+ */
+void uda1380_set_monitor(int enable)
+{
+    if (enable)
+    {
+        /* enable channel 2 */
+        uda1380_write_reg(REG_MIX_VOL, (uda1380_regs[REG_MIX_VOL] & 0x00FF) | MIX_VOL_CH_2(0));
+        uda1380_write_reg(REG_MUTE, 0);
+    } else
+    {
+        /* mute channel 2 */
+        uda1380_write_reg(REG_MUTE, MUTE_CH2);
+        uda1380_write_reg(REG_MIX_VOL, (uda1380_regs[REG_MIX_VOL] & 0x00FF) | MIX_VOL_CH_2(0xff));
+    }
+}
diff --git a/firmware/export/uda1380.h b/firmware/export/uda1380.h
index c6993ef..f7e97e1 100644
--- a/firmware/export/uda1380.h
+++ b/firmware/export/uda1380.h
@@ -17,32 +17,33 @@
  *
  ****************************************************************************/
 
-/*
- *  Driver for UDA1380 Audio-Codec
- *  2005-02-17 hubble@mochine.com
- *
- */
- 
 #ifndef _UDA1380_H
 #define _UDA1380_H
 
 extern int uda1380_init(void);
 extern void uda1380_enable_output(bool enable);
 extern int uda1380_setvol(int vol);
+extern void uda1380_set_bass(int value);
+extern void uda1380_set_treble(int value);
 extern int uda1380_mute(int mute);
 extern void uda1380_close(void);
 
-#define UDA1380_ADDR	0x30
+extern void uda1380_enable_recording(bool source_mic);
+extern void uda1380_disable_recording(void);
+extern void uda1380_set_recvol(int mic_gain, int linein_gain, int adc_volume);
+extern void uda1380_set_monitor(int enable);
+
+#define UDA1380_ADDR        0x30
 
 /* REG_0: Misc settings */
-#define REG_0    0x00
+#define REG_0               0x00
 
-#define EN_ADC	(1 << 11)       /* Enable ADC                       */
-#define EN_DEC  (1 << 10)       /* Enable Decimator                 */
-#define EN_DAC  (1 << 9)        /* Enable DAC                       */
-#define EN_INT  (1 << 8)        /* Enable Interpolator              */
-#define ADC_CLK (1 << 5)        /* ADC_CLK: WSPLL (1) SYSCLK (0)    */
-#define DAC_CLK (1 << 4)        /* DAC_CLK: WSPLL (1) SYSCLK (0)    */
+#define EN_ADC              (1 << 11)    /* Enable ADC                     */
+#define EN_DEC              (1 << 10)    /* Enable Decimator               */
+#define EN_DAC              (1 << 9)     /* Enable DAC                     */
+#define EN_INT              (1 << 8)     /* Enable Interpolator            */
+#define ADC_CLK             (1 << 5)     /* ADC_CLK: WSPLL (1) SYSCLK (0)  */
+#define DAC_CLK             (1 << 4)     /* DAC_CLK: WSPLL (1) SYSCLK (0)  */
 
 /* SYSCLK freqency select */
 #define SYSCLK_256FS        (0 << 2)
@@ -51,14 +52,14 @@
 #define SYSCLK_768FS        (3 << 2)
 
 /* WSPLL Input frequency range (kHz) */
-#define WSPLL_625_125       (0 << 0)    /* 6.25 - 12.5      */
-#define WSPLL_125_25        (1 << 0)    /* 12.5 - 25        */
-#define WSPLL_25_50         (2 << 0)    /* 25   - 50        */
-#define WSPLL_50_100        (3 << 0)    /* 50   - 100       */
+#define WSPLL_625_125       (0 << 0)     /* 6.25 - 12.5      */
+#define WSPLL_125_25        (1 << 0)     /* 12.5 - 25        */
+#define WSPLL_25_50         (2 << 0)     /* 25   - 50        */
+#define WSPLL_50_100        (3 << 0)     /* 50   - 100       */
 
 
 /* REG_I2S: I2S settings */
-#define REG_I2S     0x01
+#define REG_I2S     		0x01
 #define I2S_IFMT_IIS        (0 << 8)
 #define I2S_IFMT_LSB16      (1 << 8)
 #define I2S_IFMT_LSB18      (2 << 8)
@@ -70,71 +71,92 @@
 #define I2S_OFMT_LSB20      (3 << 0)
 #define I2S_OFMT_LSB24      (4 << 0)
 #define I2S_OFMT_MSB        (5 << 0)
-
+#define I2S_MODE_MASTER     (1 << 4)
 
 /* REG_PWR: Power control */
-#define REG_PWR     0x02
-#define PON_PLL     (1 << 15)   /* Power-on WSPLL                       */
-#define PON_HP      (1 << 13)   /* Power-on Headphone driver            */
-#define PON_DAC     (1 << 10)   /* Power-on DAC                         */
-#define PON_BIAS    (1 << 8)    /* Power-on BIAS for ADC, AVC, FSDAC    */ 
-#define EN_AVC      (1 << 7)    /* Enable analog mixer                  */
-#define PON_AVC     (1 << 6)    /* Power-on analog mixer                */
-#define PON_LNA     (1 << 4)    /* Power-on LNA & SDC                   */
-#define PON_PGAL    (1 << 3)    /* Power-on PGA left                    */
-#define PON_ADCL    (1 << 2)    /* Power-on ADC left                    */
-#define PON_PGAR    (1 << 1)    /* Power-on PGA right                   */
-#define PON_ADCR    (1 << 0)    /* Power-on ADC right                   */
+#define REG_PWR             0x02
+#define PON_PLL             (1 << 15)   /* Power-on WSPLL                     */
+#define PON_HP              (1 << 13)   /* Power-on Headphone driver          */
+#define PON_DAC             (1 << 10)   /* Power-on DAC                       */
+#define PON_BIAS            (1 << 8)    /* Power-on BIAS for ADC, AVC, FSDAC  */ 
+#define EN_AVC              (1 << 7)    /* Enable analog mixer                */
+#define PON_AVC             (1 << 6)    /* Power-on analog mixer              */
+#define PON_LNA             (1 << 4)    /* Power-on LNA & SDC                 */
+#define PON_PGAL            (1 << 3)    /* Power-on PGA left                  */
+#define PON_ADCL            (1 << 2)    /* Power-on ADC left                  */
+#define PON_PGAR            (1 << 1)    /* Power-on PGA right                 */
+#define PON_ADCR            (1 << 0)    /* Power-on ADC right                 */
 
 
 /* REG_AMIX: Analog mixer */
-#define REG_AMIX     0x03
-#define AMIX_LEFT(x)     (((x) & 0x3f) << 8)
-#define AMIX_RIGHT(x)    (((x) & 0x3f) << 0)
+#define REG_AMIX            0x03
+#define AMIX_LEFT(x)        (((x) & 0x3f) << 8)
+#define AMIX_RIGHT(x)       (((x) & 0x3f) << 0)
 
 /* REG_HP: Headphone amp */
-#define REG_HP      0x04
+#define REG_HP              0x04
 
 /* REG_MV: Master Volume control */
 #define REG_MASTER_VOL      0x10
 
-#define MASTER_VOL_RIGHT(x)     (((x) & 0xff) << 8)
-#define MASTER_VOL_LEFT(x)      (((x) & 0xff) << 0)
+#define MASTER_VOL_RIGHT(x) (((x) & 0xff) << 8)
+#define MASTER_VOL_LEFT(x)  (((x) & 0xff) << 0)
 
 /* REG_MIX: Mixer volume control */
 /* Channel 1 is from digital data from I2S */
 /* Channel 2 is from decimation filter */
 
-#define REG_MIX_VOL     0x11
-#define MIX_VOL_CHANNEL_1(x)    (((x) & 0xff) << 0)
-#define MIX_VOL_CHANNEL_2(x)    (((x) & 0xff) << 8)
+#define REG_MIX_VOL         0x11
+#define MIX_VOL_CH_1(x)     (((x) & 0xff) << 0)
+#define MIX_VOL_CH_2(x)     (((x) & 0xff) << 8)
 
 /* REG_EQ: Bass boost and tremble */
-#define REG_EQ      0x12
+#define REG_EQ              0x12
+#define EQ_MODE_FLAG        (0 << 14)
+#define EQ_MODE_MIN         (1 << 14)
+#define EQ_MODE_MAX         (3 << 14)
+#define BASSL(x)            (((x) & 0xF) << 8)
+#define BASSR(x)            (((x) & 0xF) << 0)
+#define TREBLEL(x)          (((x) & 0x3) << 12)
+#define TREBLER(x)          (((x) & 0x3) << 4)
+#define BASS_MASK           0x0F0F
+#define TREBLE_MASK         0x3030
 
-/* REG_MUTE: Master Mute */
-#define REG_MUTE    0x13
-#define MUTE_MASTER  (1 << 14)       /* Master Mute (soft)   */
-#define MUTE_CH2     (1 << 11)       /* Channel 2 mute       */
-#define MUTE_CH1     (1 << 3)        /* Channel 1 mute       */
+/* REG_MUTE: Master Mute, silence detector and oversampling */
+#define REG_MUTE            0x13
+#define MUTE_MASTER         (1 << 14)      /* Master Mute (soft)       */
+#define MIX_MODE(x)         ((x) << 12)    /* Mixer mode: See table 48 */ 
+#define MUTE_CH2            (1 << 11)      /* Channel 2 mute           */
+#define MUTE_CH1            (1 << 3)       /* Channel 1 mute           */
+
 
 /* REG_MIX_CTL: Mixer, silence detector and oversampling settings */
-#define REG_MIX_CTL  0x14
+#define REG_MIX_CTL         0x14
 #define MIX_CTL_MIX_POS     (1 << 13)
 #define MIX_CTL_MIX         (1 << 12)
 
-/* REG_DEC_VOL: Decimator Volume control */
-#define REG_DEC_VOL 0x20
+/* REG_DEC_VOL: Decimator (ADC) volume control */
+#define REG_DEC_VOL         0x20
+#define DEC_VOLL(x)         (((x) & 0xff) << 8)
+#define DEC_VOLR(x)         (((x) & 0xff) << 0)
 
 /* REG_PGA: PGA settings and mute */
-#define REG_PGA     0x21
-#define MUTE_ADC    (1 << 15)       /* Mute ADC */
+#define REG_PGA             0x21
+#define MUTE_ADC            (1 << 15)               /* Mute ADC */
+#define PGA_GAINR(x)        (((x) & 0xF) << 8)
+#define PGA_GAINL(x)        (((x) & 0xF) << 0)
+#define PGA_GAIN_MASK       0x0F0F
 
 /* REG_ADC: */
-#define REG_ADC     0x22
+#define REG_ADC             0x22
+#define SEL_LNA             (1 << 3)
+#define SEL_MIC             (1 << 2)
+#define SKIP_DCFIL          (1 << 1)
+#define EN_DCFIL            (1 << 0)
+#define VGA_GAIN(x)         (((x) & 0xF) << 8)
+#define VGA_GAIN_MASK       0x0F00
 
 /* REG_AGC: Attack / Gain */
-#define REG_AGC     0x23
-#define SKIP_DCFIL     ( 1 << 1)
+#define REG_AGC             0x23
 
 #endif /* _UDA_1380_H */
diff --git a/firmware/sound.c b/firmware/sound.c
index c8347f2..7558a33 100644
--- a/firmware/sound.c
+++ b/firmware/sound.c
@@ -498,6 +498,8 @@
 #if (CONFIG_HWCODEC == MAS3587F) || (CONFIG_HWCODEC == MAS3539F)
             tmp = ((value * 8) & 0xff) << 8;
             mas_codec_writereg(0x14, tmp & 0xff00);
+#elif defined(HAVE_UDA1380)
+            uda1380_set_bass(value >> 1);
 #elif CONFIG_HWCODEC == MAS3507D
             mas_writereg(MAS_REG_KBASS, bass_table[value+15]);
             current_bass = value * 10;
@@ -509,6 +511,8 @@
 #if (CONFIG_HWCODEC == MAS3587F) || (CONFIG_HWCODEC == MAS3539F)
             tmp = ((value * 8) & 0xff) << 8;
             mas_codec_writereg(0x15, tmp & 0xff00);
+#elif defined(HAVE_UDA1380)
+            uda1380_set_treble(value >> 1);
 #elif CONFIG_HWCODEC == MAS3507D
             mas_writereg(MAS_REG_KTREBLE, treble_table[value+15]);
             current_treble = value * 10;