summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Sevakis <jethead71@rockbox.org>2007-06-26 02:11:30 +0000
committerMichael Sevakis <jethead71@rockbox.org>2007-06-26 02:11:30 +0000
commit7fb0f71668ac574efc7e0f2b8b85d603eb24ea2a (patch)
treeb324403e582d346cadb21b5d554f7c015acf3e74
parent13de6583acdcbf14a31c64577a24a58f07acab6c (diff)
Gigabeat: Replace generic i2c driver with one that uses the CPU's builtin controller. Add some clocking registers to 'View I/O ports'.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@13720 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--apps/debug_menu.c3
-rw-r--r--firmware/SOURCES1
-rw-r--r--firmware/target/arm/s3c2440/gigabeat-fx/i2c-meg-fx.c165
-rw-r--r--firmware/target/arm/s3c2440/gigabeat-fx/i2c-meg-fx.h26
-rw-r--r--firmware/target/arm/s3c2440/gigabeat-fx/wmcodec-meg-fx.c6
5 files changed, 109 insertions, 92 deletions
diff --git a/apps/debug_menu.c b/apps/debug_menu.c
index 691e9f5070..0b39430d56 100644
--- a/apps/debug_menu.c
+++ b/apps/debug_menu.c
@@ -1178,6 +1178,9 @@ bool dbg_ports(void)
snprintf(buf, sizeof(buf), "SRCPND: %08x INTMOD: %08x", SRCPND, INTMOD); lcd_puts(0, line++, buf);
snprintf(buf, sizeof(buf), "INTMSK: %08x INTPND: %08x", INTMSK, INTPND); lcd_puts(0, line++, buf);
snprintf(buf, sizeof(buf), "CLKCON: %08x CLKSLOW: %08x", CLKCON, CLKSLOW); lcd_puts(0, line++, buf);
+ snprintf(buf, sizeof(buf), "MPLLCON: %08x UPLLCON: %08x", MPLLCON, UPLLCON); lcd_puts(0, line++, buf);
+ snprintf(buf, sizeof(buf), "CLKDIVN: %08x", CLKDIVN); lcd_puts(0, line++, buf);
+
lcd_update();
if (button_get_w_tmo(HZ/10) == (DEBUG_CANCEL|BUTTON_REL))
return false;
diff --git a/firmware/SOURCES b/firmware/SOURCES
index c642196d5c..28ef38e8db 100644
--- a/firmware/SOURCES
+++ b/firmware/SOURCES
@@ -512,7 +512,6 @@ target/arm/usb-pp.c
#ifdef GIGABEAT_F
#ifndef SIMULATOR
-drivers/generic_i2c.c
target/arm/s3c2440/gigabeat-fx/adc-meg-fx.c
target/arm/s3c2440/gigabeat-fx/ata-meg-fx.c
target/arm/s3c2440/gigabeat-fx/backlight-meg-fx.c
diff --git a/firmware/target/arm/s3c2440/gigabeat-fx/i2c-meg-fx.c b/firmware/target/arm/s3c2440/gigabeat-fx/i2c-meg-fx.c
index 670d6cd04c..45140c0f0c 100644
--- a/firmware/target/arm/s3c2440/gigabeat-fx/i2c-meg-fx.c
+++ b/firmware/target/arm/s3c2440/gigabeat-fx/i2c-meg-fx.c
@@ -7,7 +7,7 @@
* \/ \/ \/ \/ \/
* $Id$
*
- * Copyright (C) 2006 by Linus Nielsen Feltzing
+ * Copyright (C) 2007 by Michael Sevakis
*
* 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.
@@ -16,119 +16,110 @@
* KIND, either express or implied.
*
****************************************************************************/
-#include "config.h"
-#include "cpu.h"
-#include <stdbool.h>
-#include "kernel.h"
#include "system.h"
-#include "logf.h"
-#include "debug.h"
-#include "string.h"
-#include "generic_i2c.h"
-
-static void i2c_sda_output(void)
+#include "i2c-meg-fx.h"
+
+/* Only implements sending bytes for now. Adding receiving bytes should be
+ straightforward if needed. No yielding is present since the calls only
+ involve setting audio codec registers - a very rare event. */
+
+/* Wait for a condition on the bus, optionally returning it */
+#define COND_RET _c;
+#define COND_VOID
+#define WAIT_COND(cond, ret) \
+ ({ \
+ int _t = current_tick + 2; \
+ bool _c; \
+ while (1) { \
+ _c = !!(cond); \
+ if (_c || TIME_AFTER(current_tick, _t)) \
+ break; \
+ } \
+ ret \
+ })
+
+static int i2c_getack(void)
{
- GPECON |= (1 << 30);
+ /* Wait for ACK: 0 = ack received, 1 = ack not received */
+ WAIT_COND(IICCON & I2C_TXRX_INTPND, COND_VOID);
+ return IICSTAT & I2C_ACK_L;
}
-static void i2c_sda_input(void)
+static int i2c_start(void)
{
- GPECON &= ~(3 << 30);
+ /* Generate START */
+ IICSTAT = I2C_MODE_MASTER | I2C_MODE_TX | I2C_START | I2C_RXTX_ENB;
+ return i2c_getack();
}
-static void i2c_sda_lo(void)
+static void i2c_stop(void)
{
- GPEDAT &= ~(1 << 15);
+ /* Generate STOP */
+ IICSTAT = I2C_MODE_MASTER | I2C_MODE_TX | I2C_RXTX_ENB;
+ /* Clear pending interrupt to continue */
+ IICCON &= ~I2C_TXRX_INTPND;
}
-static void i2c_sda_hi(void)
+static int i2c_outb(unsigned char byte)
{
- GPEDAT |= (1 << 15);
+ /* Write byte to shift register */
+ IICDS = byte;
+ /* Clear pending interrupt to continue */
+ IICCON &= ~I2C_TXRX_INTPND;
+ return i2c_getack();
}
-static int i2c_sda(void)
+void i2c_write(int addr, const unsigned char *buf, int count)
{
- return GPEDAT & (1 << 15);
-}
+ /* Turn on I2C clock */
+ CLKCON |= (1 << 16);
-static void i2c_scl_output(void)
-{
- GPECON |= (1 << 28);
-}
+ /* Set mode to master transmitter and enable lines */
+ IICSTAT = I2C_MODE_MASTER | I2C_MODE_TX | I2C_RXTX_ENB;
-static void i2c_scl_input(void)
-{
- GPECON &= ~(3 << 28);
-}
+ /* Wait for bus to be available */
+ if (WAIT_COND(!(IICSTAT & I2C_BUSY), COND_RET))
+ {
+ /* Send slave address and then data */
+ IICCON &= ~I2C_TXRX_INTPND;
+ IICCON |= I2C_TXRX_INTENB;
-static void i2c_scl_lo(void)
-{
- GPEDAT &= ~(1 << 14);
-}
+ IICDS = addr & 0xfe;
-static int i2c_scl(void)
-{
- return GPEDAT & (1 << 14);
-}
-
-static void i2c_scl_hi(void)
-{
- i2c_scl_input();
- while(!i2c_scl());
- GPEDAT |= (1 << 14);
- i2c_scl_output();
-}
+ if (i2c_start() == 0)
+ while (count-- > 0 && i2c_outb(*buf++) == 0);
+ i2c_stop();
+ IICCON &= ~I2C_TXRX_INTENB;
+ }
-static void i2c_delay(void)
-{
- unsigned _x;
+ /* Go back to slave receive mode and disable lines */
+ IICSTAT = 0;
- /* The i2c can clock at 500KHz: 2uS period -> 1uS half period */
- /* about 30 cycles overhead + X * 7 */
- /* 300MHz: 1000nS @3.36nS/cyc = 297cyc: X = 38*/
- /* 100MHz: 1000nS @10nS/cyc = 100cyc : X = 10 */
- for (_x = 38; _x; _x--)
- {
- /* burn CPU cycles */
- /* gcc makes it an inc loop - check with objdump for asm timing */
- }
+ /* Turn off I2C clock */
+ CLKCON &= ~(1 << 16);
}
+void i2c_init(void)
+{
+ /* We poll I2C interrupts */
+ INTMSK |= (1 << 27);
+ /* Turn on I2C clock */
+ CLKCON |= (1 << 16);
-struct i2c_interface s3c2440_i2c = {
- 0x34, /* Address */
-
- /* Bit-banged interface definitions */
- i2c_scl_hi, /* Drive SCL high, might sleep on clk stretch */
- i2c_scl_lo, /* Drive SCL low */
- i2c_sda_hi, /* Drive SDA high */
- i2c_sda_lo, /* Drive SDA low */
- i2c_sda_input, /* Set SDA as input */
- i2c_sda_output, /* Set SDA as output */
- i2c_scl_input, /* Set SCL as input */
- i2c_scl_output, /* Set SCL as output */
- i2c_scl, /* Read SCL, returns 0 or nonzero */
- i2c_sda, /* Read SDA, returns 0 or nonzero */
+ /* Set GPE15 (IICSDA) and GPE14 (IICSCL) to IIC */
+ GPECON = (GPECON & ~((3 << 30) | (3 << 28))) |
+ ((2 << 30) | (2 << 28));
- i2c_delay, /* START SDA hold time (tHD:SDA) */
- i2c_delay, /* SDA hold time (tHD:DAT) */
- i2c_delay, /* SDA setup time (tSU:DAT) */
- i2c_delay, /* STOP setup time (tSU:STO) */
- i2c_delay, /* Rep. START setup time (tSU:STA) */
- i2c_delay, /* SCL high period (tHIGH) */
-};
+ /* Bus ACK, IICCLK: fPCLK / 16, Rx/Tx Int: Disable, Tx clock: IICCLK/8 */
+ /* OF PCLK: 49.1568MHz / 16 / 8 = 384.0375 kHz */
+ IICCON = (7 << 0);
-void i2c_init(void)
-{
- /* Set GPE15 (SDA) and GPE14 (SCL) to 1 */
- GPECON = (GPECON & ~(0xF<<28)) | 5<<28;
- i2c_add_node(&s3c2440_i2c);
-}
+ /* SDA line delayed 0 PCLKs */
+ IICLC = (0 << 0);
-void i2c_send(int bus_address, int reg_address, const unsigned char buf)
-{
- i2c_write_data(bus_address, reg_address, &buf, 1);
+ /* Turn off I2C clock */
+ CLKCON &= ~(1 << 16);
}
diff --git a/firmware/target/arm/s3c2440/gigabeat-fx/i2c-meg-fx.h b/firmware/target/arm/s3c2440/gigabeat-fx/i2c-meg-fx.h
index cf69230487..829b7eb91c 100644
--- a/firmware/target/arm/s3c2440/gigabeat-fx/i2c-meg-fx.h
+++ b/firmware/target/arm/s3c2440/gigabeat-fx/i2c-meg-fx.h
@@ -7,7 +7,7 @@
* \/ \/ \/ \/ \/
* $Id$
*
- * Copyright (C) 2006 by Linus Nielsen Feltzing
+ * Copyright (C) 2007 by Michael Sevakis
*
* 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.
@@ -19,4 +19,26 @@
/* chip-specific i2c functions */
-void i2c_send(int bus_address, int reg_address, const unsigned char buf);
+/* IICCON */
+#define I2C_ACKGEN (1 << 7)
+#define I2C_TXCLK_512 (1 << 6)
+#define I2C_TXRX_INTENB (1 << 5)
+#define I2C_TXRX_INTPND (1 << 4)
+
+/* IICSTAT */
+#define I2C_MODE_MASTER (2 << 6)
+#define I2C_MODE_TX (1 << 6)
+#define I2C_BUSY (1 << 5)
+#define I2C_START (1 << 5)
+#define I2C_RXTX_ENB (1 << 4)
+#define I2C_BUS_ARB_FAILED (1 << 3)
+#define I2C_S_ADDR_STAT (1 << 2)
+#define I2C_S_ADDR_MATCH (1 << 1)
+#define I2C_ACK_L (1 << 0)
+
+/* IICLC */
+#define I2C_FLT_ENB (1 << 2)
+
+void i2c_init(void);
+void i2c_write(int addr, const unsigned char *data, int count);
+
diff --git a/firmware/target/arm/s3c2440/gigabeat-fx/wmcodec-meg-fx.c b/firmware/target/arm/s3c2440/gigabeat-fx/wmcodec-meg-fx.c
index 0696b7aa0c..345991580c 100644
--- a/firmware/target/arm/s3c2440/gigabeat-fx/wmcodec-meg-fx.c
+++ b/firmware/target/arm/s3c2440/gigabeat-fx/wmcodec-meg-fx.c
@@ -26,7 +26,6 @@
#include "cpu.h"
#include "kernel.h"
#include "sound.h"
-#include "i2c.h"
#include "i2c-meg-fx.h"
void audiohw_init(void)
@@ -44,5 +43,8 @@ void audiohw_init(void)
void wmcodec_write(int reg, int data)
{
- i2c_send(0x34, (reg<<1) | ((data&0x100)>>8), data&0xff);
+ unsigned char d[2];
+ d[0] = (reg << 1) | ((data & 0x100) >> 8);
+ d[1] = data;
+ i2c_write(0x34, d, 2);
}