diff options
Diffstat (limited to 'firmware/target/arm/s3c2440/gigabeat-fx/sc606-meg-fx.c')
-rw-r--r-- | firmware/target/arm/s3c2440/gigabeat-fx/sc606-meg-fx.c | 201 |
1 files changed, 111 insertions, 90 deletions
diff --git a/firmware/target/arm/s3c2440/gigabeat-fx/sc606-meg-fx.c b/firmware/target/arm/s3c2440/gigabeat-fx/sc606-meg-fx.c index c207e310d9..e69eab432a 100644 --- a/firmware/target/arm/s3c2440/gigabeat-fx/sc606-meg-fx.c +++ b/firmware/target/arm/s3c2440/gigabeat-fx/sc606-meg-fx.c @@ -1,5 +1,6 @@ #include "config.h" #include "cpu.h" +#include <stdbool.h> #include "kernel.h" #include "system.h" #include "logf.h" @@ -8,132 +9,147 @@ #define SLAVE_ADDRESS 0xCC -#define USE_ASM - -/* This I2C driver tristates the outputs instead of driving logic high's */ +#define SDA_LO (GPHDAT &= ~(1 << 9)) +#define SDA_HI (GPHDAT |= (1 << 9)) +#define SDA_INPUT (GPHCON &= ~(3 << 18)) +#define SDA_OUTPUT (GPHCON |= (1 << 18)) #define SDA (GPHDAT & (1 << 9)) -#define SDA_LO_OUT (GPHCON |= (1 << 18));(GPHDAT &= ~(1 << 9)); -#define SDA_HI_IN (GPHCON &= ~(3 << 18)) +#define SCL_LO (GPHDAT &= ~(1 << 10)) +#define SCL_HI (GPHDAT |= (1 << 10)) +#define SCL_INPUT (GPHCON &= ~(3 << 20)) +#define SCL_OUTPUT (GPHCON |= (1 << 20)) #define SCL (GPHDAT & (1 << 10)) -#define SCL_LO_OUT (GPHCON |= (1 << 20));(GPHDAT &= ~(1 << 10)); -#define SCL_HI_IN (GPHCON &= ~(3 << 20));while(!SCL); - -/* The SC606 can clock at 400KHz: - * Clock period high is 600nS and low is 1300nS - * The high and low times are different enough to need different timings - * cycles delayed = 2 + 4 * loops - * 100MHz = 10nS per cycle: LO:1300nS=130:33 HI:600nS=60:15 - * 300MHz = 3.33nS per cycle: - * LO:1300nS=394:99 - * HI:600nS=182:21 - * MID(50/50):950(1900/2)ns=288:72 - */ - -#ifdef USE_ASM - -#define DELAY_LO 99 -#define DELAY_MID 72 -#define DELAY_HI 46 -/* This delay loop takes 4 cycles/loop to execute plus 2 for setup */ -#define DELAY(dly) \ - asm volatile( "mov r0,%0 \n" \ - "1: \n" \ - "subs r0,r0,#1 \n" \ - "bhi 1b \n" \ - : : "r"((dly)) : "r0" ); - -#else - -#define DELAY_LO 51 -#define DELAY_MID 35 -#define DELAY_HI 21 -#define DELAY(dly) do{int x;for(x=(dly);x;x--);} while (0) - -#endif + +#define SCL_SDA_HI (GPHDAT |= (3 << 9)) + +/* The SC606 can clock at 400KHz: */ +/* Clock period high is 600nS and low is 1300nS */ +/* The high and low times are different enough to need different timings */ +/* cycles delayed = 30 + 7 * loops */ +/* 100MHz = 10nS per cycle: LO:1300nS=130:14 HI:600nS=60:9 */ +/* 300MHz = 3.36nS per cycle: LO:1300nS=387:51 HI:600nS=179:21 */ +#define DELAY_LO do{int x;for(x=51;x;x--);} while (0) +#define DELAY do{int x;for(x=35;x;x--);} while (0) +#define DELAY_HI do{int x;for(x=21;x;x--);} while (0) + + static void sc606_i2c_start(void) { - SDA_HI_IN; - SCL_HI_IN; - DELAY(DELAY_MID); - SDA_LO_OUT; - DELAY(DELAY_MID); - SCL_LO_OUT; + SCL_SDA_HI; + DELAY; + SDA_LO; + DELAY; + SCL_LO; +} + +static void sc606_i2c_restart(void) +{ + SCL_SDA_HI; + DELAY; + SDA_LO; + DELAY; + SCL_LO; } static void sc606_i2c_stop(void) { - SDA_LO_OUT; - SCL_HI_IN; - DELAY(DELAY_HI); - SDA_HI_IN; + SDA_LO; + SCL_HI; + DELAY_HI; + SDA_HI; } static void sc606_i2c_ack(void) { - SDA_HI_IN; - SCL_HI_IN; - DELAY(DELAY_HI); - SCL_LO_OUT; + SDA_LO; + SCL_HI; + DELAY_HI; + SCL_LO; } -static bool sc606_i2c_getack(void) + + +static int sc606_i2c_getack(void) { - bool ret; + int ret; + + /* Don't need a delay since follows a data bit with a delay on the end */ + SDA_INPUT; /* And set to input */ + DELAY; + SCL_HI; - SDA_HI_IN; - DELAY(DELAY_MID); - SCL_HI_IN; + ret = (SDA != 0); /* ack failed if SDA is not low */ + DELAY_HI; - ret = !SDA; + SCL_LO; + DELAY_LO; - SCL_LO_OUT; - DELAY(DELAY_LO); + SDA_HI; + SDA_OUTPUT; + DELAY_LO; return ret; } + + static void sc606_i2c_outb(unsigned char byte) { int i; /* clock out each bit, MSB first */ - for ( i=0x80; i; i>>=1 ) + for (i = 0x80; i; i >>= 1) { - if ( i & byte ) - SDA_HI_IN; + if (i & byte) + { + SDA_HI; + } else - SDA_LO_OUT; - DELAY(DELAY_MID); - SCL_HI_IN; - DELAY(DELAY_HI); - SCL_LO_OUT; + { + SDA_LO; + } + DELAY; + + SCL_HI; + DELAY_HI; + + SCL_LO; + DELAY_LO; } + + SDA_HI; + } + + static unsigned char sc606_i2c_inb(void) { - int i; - unsigned char byte = 0; + int i; + unsigned char byte = 0; - /* clock in each bit, MSB first */ - SDA_HI_IN; - for ( i=0x80; i; i>>=1 ) - { - SCL_HI_IN; - DELAY(DELAY_HI); - if ( SDA ) - byte |= i; - SCL_LO_OUT; - DELAY(DELAY_LO); - } + SDA_INPUT; /* And set to input */ + /* clock in each bit, MSB first */ + for (i = 0x80; i; i >>= 1) { + SCL_HI; + + if (SDA) + byte |= i; - sc606_i2c_ack(); - return byte; + SCL_LO; + } + SDA_OUTPUT; + + sc606_i2c_ack(); + + return byte; } + + /* returns number of acks that were bad */ int sc606_write(unsigned char reg, unsigned char data) { @@ -147,7 +163,7 @@ int sc606_write(unsigned char reg, unsigned char data) sc606_i2c_outb(reg); x += sc606_i2c_getack(); - sc606_i2c_start(); + sc606_i2c_restart(); sc606_i2c_outb(SLAVE_ADDRESS); x += sc606_i2c_getack(); @@ -160,6 +176,8 @@ int sc606_write(unsigned char reg, unsigned char data) return x; } + + int sc606_read(unsigned char reg, unsigned char* data) { int x; @@ -171,7 +189,7 @@ int sc606_read(unsigned char reg, unsigned char* data) sc606_i2c_outb(reg); x += sc606_i2c_getack(); - sc606_i2c_start(); + sc606_i2c_restart(); sc606_i2c_outb(SLAVE_ADDRESS | 1); x += sc606_i2c_getack(); @@ -181,6 +199,8 @@ int sc606_read(unsigned char reg, unsigned char* data) return x; } + + void sc606_init(void) { volatile int i; @@ -194,11 +214,12 @@ void sc606_init(void) /* About 400us - needs 350us */ for (i = 200; i; i--) - DELAY(DELAY_LO); + { + DELAY_LO; + } /* Set GPH9 (SDA) and GPH10 (SCL) to 1 */ GPHUP &= ~(3<<9); - SCL_HI_IN; - SDA_HI_IN; + GPHCON = (GPHCON & ~(0xF<<18)) | 5<<18; } |