summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDave Chapman <dave@dchapman.com>2006-02-05 17:16:34 +0000
committerDave Chapman <dave@dchapman.com>2006-02-05 17:16:34 +0000
commit465596b1639393ef320decced442537133ab09e8 (patch)
tree79c88e59c7ab15e2dab33caf045835b5a118a2e9
parentd16a8b8845ed496e9375c5dfac6da2011c9eb362 (diff)
downloadrockbox-465596b1639393ef320decced442537133ab09e8.zip
rockbox-465596b1639393ef320decced442537133ab09e8.tar.gz
rockbox-465596b1639393ef320decced442537133ab09e8.tar.bz2
rockbox-465596b1639393ef320decced442537133ab09e8.tar.xz
More iPod 3G code from Seven Le Mesle
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@8582 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--firmware/drivers/ata.c33
-rw-r--r--firmware/drivers/button.c139
-rw-r--r--firmware/drivers/i2c-pp5002.c168
-rw-r--r--firmware/drivers/pcf50605.c4
-rw-r--r--firmware/drivers/power.c8
-rw-r--r--firmware/drivers/serial.c6
-rw-r--r--firmware/drivers/wm8731l.c268
7 files changed, 610 insertions, 16 deletions
diff --git a/firmware/drivers/ata.c b/firmware/drivers/ata.c
index 3c79c1b..a5fb78d 100644
--- a/firmware/drivers/ata.c
+++ b/firmware/drivers/ata.c
@@ -71,13 +71,20 @@
#define SET_REG(reg,val) reg = ((val) << 8)
#define SET_16BITREG(reg,val) reg = (val)
-#elif CONFIG_CPU == PP5020
+#elif (CONFIG_CPU == PP5002) || (CONFIG_CPU == PP5020)
/* don't use sh7034 assembler routines */
#define PREFER_C_READING
#define PREFER_C_WRITING
+#if (CONFIG_CPU == PP5002)
+#define ATA_IOBASE 0xc00031e0
+#define ATA_CONTROL (*((volatile unsigned char*)(0xc00033f8)))
+#elif (CONFIG_CPU == PP5020)
#define ATA_IOBASE 0xc30001e0
+#define ATA_CONTROL (*((volatile unsigned char*)(0xc30003f8)))
+#endif
+
#define ATA_DATA (*((volatile unsigned short*)(ATA_IOBASE)))
#define ATA_ERROR (*((volatile unsigned char*)(ATA_IOBASE + 0x04)))
#define ATA_NSECTOR (*((volatile unsigned char*)(ATA_IOBASE + 0x08)))
@@ -86,7 +93,6 @@
#define ATA_HCYL (*((volatile unsigned char*)(ATA_IOBASE + 0x14)))
#define ATA_SELECT (*((volatile unsigned char*)(ATA_IOBASE + 0x18)))
#define ATA_COMMAND (*((volatile unsigned char*)(ATA_IOBASE + 0x1c)))
-#define ATA_CONTROL (*((volatile unsigned char*)(0xc30003f8)))
#define STATUS_BSY 0x80
#define STATUS_RDY 0x40
@@ -928,6 +934,11 @@ extern void ata_flush(void)
static int check_registers(void)
{
+#if (CONFIG_CPU == PP5002)
+ /* This fails on the PP5002, but the ATA driver still works. This
+ needs more investigation. */
+ return 0;
+#else
int i;
if ( ATA_STATUS & STATUS_BSY )
return -1;
@@ -939,13 +950,14 @@ static int check_registers(void)
SET_REG(ATA_HCYL, WRITE_PATTERN4);
if ((ATA_NSECTOR == READ_PATTERN1) &&
- (ATA_SECTOR == READ_PATTERN2) &&
- (ATA_LCYL == READ_PATTERN3) &&
- (ATA_HCYL == READ_PATTERN4))
+ (ATA_SECTOR == READ_PATTERN2) &&
+ (ATA_LCYL == READ_PATTERN3) &&
+ (ATA_HCYL == READ_PATTERN4))
return 0;
}
return -2;
+#endif
}
static int freeze_lock(void)
@@ -1254,7 +1266,7 @@ void ata_enable(bool on)
(void)on;
#elif CONFIG_CPU == TCC730
-#elif CONFIG_CPU == PP5020
+#elif (CONFIG_CPU == PP5002) || (CONFIG_CPU == PP5020)
/* TODO: Implement ata_enable() */
(void)on;
#endif
@@ -1410,7 +1422,7 @@ int ata_init(void)
#elif defined(IAUDIO_X5)
/* X5 TODO */
bool coldstart = true;
-#elif CONFIG_CPU == PP5020
+#elif (CONFIG_CPU == PP5002) || (CONFIG_CPU == PP5020)
bool coldstart = false;
/* TODO: Implement coldstart variable */
#else
@@ -1440,6 +1452,13 @@ int ata_init(void)
or_l(0x00080000, &GPIO_FUNCTION);
/* FYI: The IDECONFIGx registers are set by set_cpu_frequency() */
+#elif CONFIG_CPU == PP5002
+ /* From ipod-ide.c:ipod_ide_register() */
+ outl(inl(0xc0003024) | (1 << 7), 0xc0003024);
+ outl(inl(0xc0003024) & ~(1<<2), 0xc0003024);
+
+ outl(0x10, 0xc0003000);
+ outl(0x80002150, 0xc0003004);
#elif CONFIG_CPU == PP5020
/* From ipod-ide.c:ipod_ide_register() */
outl(inl(0xc3000028) | (1 << 5), 0xc3000028);
diff --git a/firmware/drivers/button.c b/firmware/drivers/button.c
index 654852c..5098cbe 100644
--- a/firmware/drivers/button.c
+++ b/firmware/drivers/button.c
@@ -61,7 +61,8 @@ static bool flipped; /* buttons can be flipped to match the LCD flip */
#define REPEAT_INTERVAL_FINISH 5
/* the power-off button and number of repeated keys before shutting off */
-#if (CONFIG_KEYPAD == IPOD_4G_PAD) || (CONFIG_KEYPAD == IRIVER_IFP7XX_PAD)
+#if (CONFIG_KEYPAD == IPOD_3G_PAD) || (CONFIG_KEYPAD == IPOD_4G_PAD) ||\
+ (CONFIG_KEYPAD == IRIVER_IFP7XX_PAD)
#define POWEROFF_BUTTON BUTTON_PLAY
#define POWEROFF_COUNT 40
#else
@@ -220,7 +221,132 @@ void ipod_4g_button_int(void)
CPU_HI_INT_EN = I2C_MASK;
}
#endif
+#if CONFIG_KEYPAD == IPOD_3G_PAD
+/* Variable to use for setting button status in interrupt handler */
+int int_btn = BUTTON_NONE;
+/**
+ *
+ *
+ */
+void handle_scroll_wheel(int new_scroll, int was_hold, int reverse)
+{
+ int wheel_keycode = BUTTON_NONE;
+ static int prev_scroll = -1;
+ static int scroll_state[4][4] = {
+ {0, 1, -1, 0},
+ {-1, 0, 0, 1},
+ {1, 0, 0, -1},
+ {0, -1, 1, 0}
+ };
+
+ if ( prev_scroll == -1 ) {
+ prev_scroll = new_scroll;
+ }
+ else if (!was_hold) {
+ switch (scroll_state[prev_scroll][new_scroll]) {
+ case 1:
+ if (reverse) {
+ /* 'r' keypress */
+ wheel_keycode = BUTTON_SCROLL_FWD;
+ }
+ else {
+ /* 'l' keypress */
+ wheel_keycode = BUTTON_SCROLL_BACK;
+ }
+ break;
+ case -1:
+ if (reverse) {
+ /* 'l' keypress */
+ wheel_keycode = BUTTON_SCROLL_BACK;
+ }
+ else {
+ /* 'r' keypress */
+ wheel_keycode = BUTTON_SCROLL_FWD;
+ break;
+ default:
+ /* only happens if we get out of sync */
+ break;
+ }
+ }
+ }
+ if (wheel_keycode != BUTTON_NONE)
+ queue_post(&button_queue, wheel_keycode, NULL);
+ prev_scroll = new_scroll;
+}
+
+static int ipod_3g_button_read(void)
+{
+ unsigned char source, state;
+ static int was_hold = 0;
+int btn = BUTTON_NONE;
+ /*
+ * we need some delay for g3, cause hold generates several interrupts,
+ * some of them delayed
+ */
+ udelay(250);
+
+ /* get source of interupts */
+ source = inb(0xcf000040);
+ if (source) {
+
+ /* get current keypad status */
+ state = inb(0xcf000030);
+ outb(~state, 0xcf000060);
+
+ if (was_hold && source == 0x40 && state == 0xbf) {
+ /* ack any active interrupts */
+ outb(source, 0xcf000070);
+ return BUTTON_NONE;
+ }
+ was_hold = 0;
+
+
+ if ( source & 0x20 ) {
+ /* 3g hold switch is active low */
+ btn |= BUTTON_HOLD;
+ was_hold = 1;
+ /* hold switch on 3g causes all outputs to go low */
+ /* we shouldn't interpret these as key presses */
+ goto done;
+ }
+ if (source & 0x1) {
+ btn |= BUTTON_RIGHT;
+ }
+ if (source & 0x2) {
+ btn |= BUTTON_SELECT;
+ }
+ if (source & 0x4) {
+ btn |= BUTTON_PLAY;
+ }
+ if (source & 0x8) {
+ btn |= BUTTON_LEFT;
+ }
+ if (source & 0x10) {
+ btn |= BUTTON_MENU;
+ }
+
+ if (source & 0xc0) {
+ handle_scroll_wheel((state & 0xc0) >> 6, was_hold, 0);
+ }
+ done:
+
+ /* ack any active interrupts */
+ outb(source, 0xcf000070);
+ }
+ return btn;
+}
+
+void ipod_3g_button_int(void)
+{
+ /**
+ * Theire is other things to do but for now ...
+ * TODO: implement this function in a better way
+ **/
+ int_btn = ipod_3g_button_read();
+
+}
+#endif
static void button_tick(void)
{
static int tick = 0;
@@ -404,8 +530,13 @@ void button_init(void)
GPIOA_INT_EN = 0x20;
CPU_INT_EN = 0x40000000;
CPU_HI_INT_EN = I2C_MASK;
-#endif /* CONFIG_KEYPAD */
+#elif CONFIG_KEYPAD == IPOD_3G_PAD
+ outb(~inb(GPIOA_INPUT_VAL), GPIOA_INT_LEV);
+ outb(inb(GPIOA_INT_STAT), GPIOA_INT_CLR);
+ outb(0xff, GPIOA_INT_EN);
+
+#endif /* CONFIG_KEYPAD */
queue_init(&button_queue);
button_read();
lastbtn = button_read();
@@ -418,7 +549,7 @@ void button_init(void)
}
#ifdef HAVE_LCD_BITMAP /* only bitmap displays can be flipped */
-#if (CONFIG_KEYPAD != IPOD_4G_PAD)
+#if (CONFIG_KEYPAD != IPOD_3G_PAD) && (CONFIG_KEYPAD != IPOD_4G_PAD)
/*
* helper function to swap UP/DOWN, LEFT/RIGHT (and F1/F3 for Recorder)
*/
@@ -883,7 +1014,7 @@ static int button_read(void)
if (data & 0x01)
btn |= BUTTON_ON;
-#elif CONFIG_KEYPAD == IPOD_4G_PAD
+#elif (CONFIG_KEYPAD == IPOD_3G_PAD) || (CONFIG_KEYPAD == IPOD_4G_PAD)
(void)data;
/* The int_btn variable is set in the button interrupt handler */
btn = int_btn;
diff --git a/firmware/drivers/i2c-pp5002.c b/firmware/drivers/i2c-pp5002.c
new file mode 100644
index 0000000..dc26d8a
--- /dev/null
+++ b/firmware/drivers/i2c-pp5002.c
@@ -0,0 +1,168 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * PP5002 I2C driver
+ *
+ * Based on code from the ipodlinux project - http://ipodlinux.org/
+ * Adapted for Rockbox in January 2006
+ *
+ * Original file: linux/arch/armnommu/mach-ipod/hardware.c
+ *
+ * Copyright (c) 2003-2005 Bernard Leach (leachbj@bouncycastle.org)
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include "cpu.h"
+#include "kernel.h"
+#include "logf.h"
+#include "system.h"
+#include "i2c-pp5002.h"
+
+/* Local functions definitions */
+
+#define IPOD_I2C_BASE 0xc0008000
+#define IPOD_I2C_CTRL (IPOD_I2C_BASE+0x00)
+#define IPOD_I2C_ADDR (IPOD_I2C_BASE+0x04)
+#define IPOD_I2C_DATA0 (IPOD_I2C_BASE+0x0c)
+#define IPOD_I2C_DATA1 (IPOD_I2C_BASE+0x10)
+#define IPOD_I2C_DATA2 (IPOD_I2C_BASE+0x14)
+#define IPOD_I2C_DATA3 (IPOD_I2C_BASE+0x18)
+#define IPOD_I2C_STATUS (IPOD_I2C_BASE+0x1c)
+
+/* IPOD_I2C_CTRL bit definitions */
+#define IPOD_I2C_SEND 0x80
+
+/* IPOD_I2C_STATUS bit definitions */
+#define IPOD_I2C_BUSY (1<<6)
+
+#define POLL_TIMEOUT (HZ)
+
+static int ipod_i2c_wait_not_busy(void)
+{
+ unsigned long timeout;
+ timeout = current_tick + POLL_TIMEOUT;
+ while (TIME_BEFORE(current_tick, timeout)) {
+ if (!(inb(IPOD_I2C_STATUS) & IPOD_I2C_BUSY)) {
+ return 0;
+ }
+ yield();
+ }
+
+ return -1;
+}
+
+
+/* Public functions */
+
+int ipod_i2c_read_byte(unsigned int addr, unsigned int *data)
+{
+ if (ipod_i2c_wait_not_busy() < 0)
+ {
+ return -1;
+ }
+
+ /* clear top 15 bits, left shift 1, or in 0x1 for a read */
+ outb(((addr << 17) >> 16) | 0x1, IPOD_I2C_ADDR);
+
+ outb(inb(IPOD_I2C_CTRL) | 0x20, IPOD_I2C_CTRL);
+
+ outb(inb(IPOD_I2C_CTRL) | IPOD_I2C_SEND, IPOD_I2C_CTRL);
+
+ if (ipod_i2c_wait_not_busy() < 0)
+ {
+ return -1;
+ }
+
+ if (data)
+ {
+ *data = inb(IPOD_I2C_DATA0);
+ }
+
+ return 0;
+}
+
+int ipod_i2c_send_bytes(unsigned int addr, unsigned int len, unsigned char *data)
+{
+ int data_addr;
+ unsigned int i;
+
+ if (len < 1 || len > 4)
+ {
+ return -1;
+ }
+
+ if (ipod_i2c_wait_not_busy() < 0)
+ {
+ return -2;
+ }
+
+ /* clear top 15 bits, left shift 1 */
+ outb((addr << 17) >> 16, IPOD_I2C_ADDR);
+
+ outb(inb(IPOD_I2C_CTRL) & ~0x20, IPOD_I2C_CTRL);
+
+ data_addr = IPOD_I2C_DATA0;
+ for ( i = 0; i < len; i++ )
+ {
+ outb(*data++, data_addr);
+ data_addr += 4;
+ }
+
+ outb((inb(IPOD_I2C_CTRL) & ~0x26) | ((len-1) << 1), IPOD_I2C_CTRL);
+
+ outb(inb(IPOD_I2C_CTRL) | IPOD_I2C_SEND, IPOD_I2C_CTRL);
+
+ return 0x0;
+}
+
+int ipod_i2c_send_byte(unsigned int addr, int data0)
+{
+ unsigned char data[1];
+
+ data[0] = data0;
+
+ return ipod_i2c_send_bytes(addr, 1, data);
+}
+
+
+int i2c_readbyte(unsigned int dev_addr, int addr)
+{
+ int data;
+
+ ipod_i2c_send_byte(dev_addr, addr);
+ ipod_i2c_read_byte(dev_addr, &data);
+
+ return data;
+}
+
+int ipod_i2c_send(unsigned int addr, int data0, int data1)
+{
+ unsigned char data[2];
+
+ data[0] = data0;
+ data[1] = data1;
+
+ return ipod_i2c_send_bytes(addr, 2, data);
+}
+
+void i2c_init(void)
+{
+ /* From ipodlinux */
+
+ outl(inl(0xcf005000) | 0x2, 0xcf005000);
+
+ outl(inl(0xcf005030) | (1<<8), 0xcf005030);
+ outl(inl(0xcf005030) & ~(1<<8), 0xcf005030);
+}
diff --git a/firmware/drivers/pcf50605.c b/firmware/drivers/pcf50605.c
index d205f89..122ba6e 100644
--- a/firmware/drivers/pcf50605.c
+++ b/firmware/drivers/pcf50605.c
@@ -24,7 +24,11 @@
*
****************************************************************************/
#include "config.h"
+#if CONFIG_I2C == I2C_PP5020
#include "i2c-pp5020.h"
+#elif CONFIG_I2C == I2C_PP5002
+#include "i2c-pp5002.h"
+#endif
#include "rtc.h"
#define OOCS 0x01
diff --git a/firmware/drivers/power.c b/firmware/drivers/power.c
index e91d8a2..2150040 100644
--- a/firmware/drivers/power.c
+++ b/firmware/drivers/power.c
@@ -84,7 +84,7 @@ void power_init(void)
pcf50606_init();
#endif
#endif
-#elif CONFIG_CPU == PP5020
+#elif CONFIG_CPU == PP5020 || CONFIG_CPU == PP5002
/* TODO: Implement power_init() */
#else
#ifdef HAVE_POWEROFF_ON_PB5
@@ -181,7 +181,7 @@ void ide_power_enable(bool on)
or_l(0x80000000, &GPIO_OUT);
#elif defined(IAUDIO_X5)
/* X5 TODO */
-#elif CONFIG_CPU == PP5020
+#elif (CONFIG_CPU == PP5002) || (CONFIG_CPU == PP5020)
/* We do nothing on the iPod */
#elif defined(GMINI_ARCH)
if(on)
@@ -237,7 +237,7 @@ bool ide_powered(void)
return (GPIO_OUT & 0x80000000)?false:true;
#elif defined(IAUDIO_X5)
return false; /* X5 TODO */
-#elif CONFIG_CPU == PP5020
+#elif (CONFIG_CPU == PP5002) || (CONFIG_CPU == PP5020)
/* pretend we are always powered - we don't turn it off on the ipod */
return true;
#elif defined(GMINI_ARCH)
@@ -273,7 +273,7 @@ void power_off(void)
and_l(~0x00080000, &GPIO1_OUT);
#elif defined(IAUDIO_X5)
and_l(~0x00000008, &GPIO_OUT);
-#elif CONFIG_CPU == PP5020
+#elif (CONFIG_CPU == PP5002) || (CONFIG_CPU == PP5002)
#ifndef BOOTLOADER
/* We don't turn off the ipod, we put it in a deep sleep */
pcf50605_standby_mode();
diff --git a/firmware/drivers/serial.c b/firmware/drivers/serial.c
index b491b13..8479da5 100644
--- a/firmware/drivers/serial.c
+++ b/firmware/drivers/serial.c
@@ -27,7 +27,11 @@
#include "lcd.h"
#include "serial.h"
-#if (CONFIG_CPU != MCF5249) && (CONFIG_CPU != TCC730) && (CONFIG_CPU != PP5020) && (CONFIG_CPU != PNX0101) && (CONFIG_CPU != MCF5250)
+
+#if (CONFIG_CPU != MCF5249) && (CONFIG_CPU != TCC730) && \
+ (CONFIG_CPU != PP5020) && (CONFIG_CPU != PNX0101) && \
+ (CONFIG_CPU != PP5002) && (CONFIG_CPU != MCF5250)
+
/* FIX: this doesn't work on iRiver or Gmini or iPod yet */
/* iFP7xx has no remote */
diff --git a/firmware/drivers/wm8731l.c b/firmware/drivers/wm8731l.c
new file mode 100644
index 0000000..d49e8f4
--- /dev/null
+++ b/firmware/drivers/wm8731l.c
@@ -0,0 +1,268 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Driver for WM8731L audio codec
+ *
+ * Based on code from the ipodlinux project - http://ipodlinux.org/
+ * Adapted for Rockbox in January 2006
+ *
+ * Original file: linux/arch/armnommu/mach-ipod/audio.c
+ *
+ * Copyright (c) 2003-2005 Bernard Leach (leachbj@bouncycastle.org)
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#include "lcd.h"
+#include "cpu.h"
+#include "kernel.h"
+#include "thread.h"
+#include "power.h"
+#include "debug.h"
+#include "system.h"
+#include "sprintf.h"
+#include "button.h"
+#include "string.h"
+#include "file.h"
+#include "buffer.h"
+#include "audio.h"
+
+#include "i2c-pp5002.h"
+#include "wm8731l.h"
+#include "pcf50605.h"
+
+void wm8731l_reset(void);
+
+#define IPOD_PCM_LEVEL 0x65 /* -6dB */
+
+#define RESET (0x0f<<1)
+#define PWRMGMT1 (0x19<<1)
+#define PWRMGMT2 (0x1a<<1)
+#define AINTFCE (0x07<<1)
+#define LOUT1VOL (0x02<<1)
+#define ROUT1VOL (0x03<<1)
+#define LOUT2VOL (0x28<<1)
+#define ROUT2VOL (0x29<<1)
+
+int wm8731l_mute(int mute)
+{
+ if (mute)
+ {
+ /* Set DACMU = 1 to soft-mute the audio DACs. */
+ ipod_i2c_send(0x1a, 0xa, 0x8);
+ } else {
+ /* Set DACMU = 0 to soft-un-mute the audio DACs. */
+ ipod_i2c_send(0x1a, 0xa, 0x0);
+ }
+
+ return 0;
+}
+/** From ipodLinux **/
+static void codec_set_active(int active)
+{
+ /* set active to 0x0 or 0x1 */
+ if (active) {
+ ipod_i2c_send(0x1a, 0x12, 0x01);
+ } else {
+ ipod_i2c_send(0x1a, 0x12, 0x00);
+ }
+}
+
+/*
+ * Reset the I2S BIT.FORMAT I2S, 16bit, FIFO.FORMAT 32bit
+ */
+static void i2s_reset(void)
+{
+ /* I2S device reset */
+ outl(inl(0xcf005030) | 0x80, 0xcf005030);
+ outl(inl(0xcf005030) & ~0x80, 0xcf005030);
+
+ /* I2S controller enable */
+ outl(inl(0xc0002500) | 0x1, 0xc0002500);
+
+ /* BIT.FORMAT [11:10] = I2S (default) */
+ /* BIT.SIZE [9:8] = 24bit */
+ /* FIFO.FORMAT = 24 bit LSB */
+
+ /* reset DAC and ADC fifo */
+ outl(inl(0xc000251c) | 0x30000, 0xc000251c);
+}
+
+/*
+ * Initialise the WM8975 for playback via headphone and line out.
+ * Note, I'm using the WM8750 datasheet as its apparently close.
+ */
+int wm8731l_init(void) {
+ /* reset I2C */
+ i2c_init();
+
+ /* device reset */
+ outl(inl(0xcf005030) | 0x80, 0xcf005030);
+ outl(inl(0xcf005030) & ~0x80, 0xcf005030);
+
+ /* device enable */
+ outl(inl(0xcf005000) | 0x80, 0xcf005000);
+
+ /* GPIO D06 enable for output */
+ outl(inl(0xcf00000c) | 0x40, 0xcf00000c);
+ outl(inl(0xcf00001c) & ~0x40, 0xcf00001c);
+ /* bits 11,10 == 01 */
+ outl(inl(0xcf004040) | 0x400, 0xcf004040);
+ outl(inl(0xcf004040) & ~0x800, 0xcf004040);
+
+ outl(inl(0xcf004048) & ~0x1, 0xcf004048);
+
+ outl(inl(0xcf000004) & ~0xf, 0xcf000004);
+ outl(inl(0xcf004044) & ~0xf, 0xcf004044);
+
+ /* C03 = 0 */
+ outl(inl(0xcf000008) | 0x8, 0xcf000008);
+ outl(inl(0xcf000018) | 0x8, 0xcf000018);
+ outl(inl(0xcf000028) & ~0x8, 0xcf000028);
+
+ return 0;
+}
+
+/* Silently enable / disable audio output */
+void wm8731l_enable_output(bool enable)
+{
+ if (enable)
+ {
+ /* reset the I2S controller into known state */
+ i2s_reset();
+
+ ipod_i2c_send(0x1a, 0x1e, 0x0); /*Reset*/
+
+ codec_set_active(0x0);
+
+ /* DACSEL=1 */
+ /* BYPASS=1 */
+ ipod_i2c_send(0x1a, 0x8, 0x18);
+
+ /* set power register to POWEROFF=0 on OUTPD=0, DACPD=0 */
+ ipod_i2c_send(0x1a, 0xc, 0x67);
+
+ /* BCLKINV=0(Dont invert BCLK) MS=1(Enable Master) LRSWAP=0 LRP=0 */
+ /* IWL=00(16 bit) FORMAT=10(I2S format) */
+ ipod_i2c_send(0x1a, 0xe, 0x42);
+
+ wm8731l_set_sample_rate(WM8731L_44100HZ);
+
+ /* set the volume to -6dB */
+ ipod_i2c_send(0x1a, 0x4, IPOD_PCM_LEVEL);
+ ipod_i2c_send(0x1a, 0x6 | 0x1, IPOD_PCM_LEVEL);
+
+ /* ACTIVE=1 */
+ codec_set_active(1);
+
+ /* 5. Set DACMU = 0 to soft-un-mute the audio DACs. */
+ ipod_i2c_send(0x1a, 0xa, 0x0);
+
+ wm8731l_mute(0);
+ } else {
+ wm8731l_mute(1);
+ }
+}
+
+int wm8731l_set_master_vol(int vol_l, int vol_r)
+{
+ /* +6 to -73dB 1dB steps (plus mute == 80levels) 7bits */
+ /* 1111111 == +6dB */
+ /* 1111001 == 0dB */
+ /* 0110000 == -73dB */
+ /* 0101111 == mute (0x2f) */
+ if (vol_l == vol_r) {
+ ipod_i2c_send(0x1a, 0x4 | 0x1, vol_l);
+ } else {
+ ipod_i2c_send(0x1a, 0x4, vol_l);
+ ipod_i2c_send(0x1a, 0x6, vol_r);
+ }
+
+ return 0;
+}
+
+int wm8975_set_mixer_vol(int channel1, int channel2)
+{
+ (void)channel1;
+ (void)channel2;
+
+ return 0;
+}
+
+void wm8731l_set_bass(int value)
+{
+ (void)value;
+}
+
+void wm8731l_set_treble(int value)
+{
+ (void)value;
+}
+
+/* Nice shutdown of WM8975 codec */
+void wm8731l_close(void)
+{
+ /* set DACMU=1 DEEMPH=0 */
+ ipod_i2c_send(0x1a, 0xa, 0x8);
+
+ /* ACTIVE=0 */
+ codec_set_active(0x0);
+
+ /* line in mute left & right*/
+ ipod_i2c_send(0x1a, 0x0 | 0x1, 0x80);
+
+ /* set DACSEL=0, MUTEMIC=1 */
+ ipod_i2c_send(0x1a, 0x8, 0x2);
+
+ /* set POWEROFF=0 OUTPD=0 DACPD=1 */
+ ipod_i2c_send(0x1a, 0xc, 0x6f);
+
+ /* set POWEROFF=1 OUTPD=1 DACPD=1 */
+ ipod_i2c_send(0x1a, 0xc, 0xff);
+}
+
+/* Change the order of the noise shaper, 5th order is recommended above 32kHz */
+void wm8731l_set_nsorder(int order)
+{
+ (void)order;
+}
+
+/* */
+void wm8731l_set_sample_rate(int sampling_control)
+{
+ codec_set_active(0x0);
+ ipod_i2c_send(0x1a, 0x10, sampling_control);
+ codec_set_active(0x1);
+}
+
+void wm8731l_enable_recording(bool source_mic)
+{
+ (void)source_mic;
+}
+
+void wm8731l_disable_recording(void)
+{
+
+}
+
+void wm8731l_set_recvol(int left, int right, int type)
+{
+ (void)left;
+ (void)right;
+ (void)type;
+}
+
+void wm8731l_set_monitor(int enable)
+{
+ (void)enable;
+}