From 7fb0f71668ac574efc7e0f2b8b85d603eb24ea2a Mon Sep 17 00:00:00 2001 From: Michael Sevakis Date: Tue, 26 Jun 2007 02:11:30 +0000 Subject: 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 --- apps/debug_menu.c | 3 + firmware/SOURCES | 1 - .../target/arm/s3c2440/gigabeat-fx/i2c-meg-fx.c | 165 ++++++++++----------- .../target/arm/s3c2440/gigabeat-fx/i2c-meg-fx.h | 26 +++- .../arm/s3c2440/gigabeat-fx/wmcodec-meg-fx.c | 6 +- 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 -#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); } -- cgit v1.2.3