From 784dd787456b8c1f52a98559d645714760cd0ad4 Mon Sep 17 00:00:00 2001 From: Michael Sevakis Date: Wed, 25 Oct 2006 23:24:07 +0000 Subject: Moved pcf50606 stuff to target directory. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@11348 a1c6a512-1295-4272-9138-f99709370657 --- firmware/SOURCES | 6 +- firmware/export/pcf50606.h | 7 +- firmware/powermgmt.c | 14 +- firmware/target/coldfire/iaudio/x5/pcf50606-x5.c | 518 +------------------- .../target/coldfire/iriver/h300/pcf50606-h300.c | 52 ++ firmware/target/coldfire/pcf50606-coldfire.c | 540 +++++++++++++++++++++ 6 files changed, 609 insertions(+), 528 deletions(-) create mode 100644 firmware/target/coldfire/iriver/h300/pcf50606-h300.c create mode 100644 firmware/target/coldfire/pcf50606-coldfire.c (limited to 'firmware') diff --git a/firmware/SOURCES b/firmware/SOURCES index 92a41cdead..171cd6db12 100644 --- a/firmware/SOURCES +++ b/firmware/SOURCES @@ -138,9 +138,6 @@ drivers/i2c.c #if CONFIG_CODEC != SWCODEC drivers/mas.c #endif -#ifdef IRIVER_H300_SERIES -drivers/pcf50606.c -#endif #ifdef HAVE_EEPROM drivers/eeprom_24cxx.c #ifdef HAVE_EEPROM_SETTINGS @@ -242,6 +239,7 @@ target/coldfire/iaudio/x5/power-x5.c target/coldfire/iaudio/x5/button-x5.c target/coldfire/iaudio/x5/lcd-as-x5.S target/coldfire/iaudio/x5/lcd-x5.c +target/coldfire/pcf50606-coldfire.c target/coldfire/iaudio/x5/pcf50606-x5.c target/coldfire/iaudio/x5/adc-x5.c target/coldfire/iaudio/x5/ata-x5.c @@ -256,6 +254,8 @@ target/coldfire/iaudio/x5/lcd-remote-x5.c #ifdef IRIVER_H300_SERIES #ifndef SIMULATOR target/coldfire/iriver/h300/lcd-as-h300.S +target/coldfire/pcf50606-coldfire.c +target/coldfire/iriver/h300/pcf50606-h300.c #endif #endif diff --git a/firmware/export/pcf50606.h b/firmware/export/pcf50606.h index 3e567c963c..1f4b6ba3ad 100644 --- a/firmware/export/pcf50606.h +++ b/firmware/export/pcf50606.h @@ -20,13 +20,14 @@ #define PCF50606_H void pcf50606_init(void); -void pcf50606_i2c_recalc_delay(int cpu_clock); int pcf50606_write_multiple(int address, const unsigned char* buf, int count); int pcf50606_write(int address, unsigned char val); int pcf50606_read_multiple(int address, unsigned char* buf, int count); int pcf50606_read(int address); /* internal low level calls used by the eeprom driver for h300 */ +void pcf50606_i2c_init(void); +void pcf50606_i2c_recalc_delay(int cpu_clock); void pcf50606_i2c_start(void); void pcf50606_i2c_stop(void); void pcf50606_i2c_ack(bool ack); @@ -34,4 +35,8 @@ bool pcf50606_i2c_getack(void); void pcf50606_i2c_outb(unsigned char byte); unsigned char pcf50606_i2c_inb(bool ack); +#if defined(IAUDIO_X5) && !defined(SIMULATOR) +void pcf50606_reset_timeout(void); #endif + +#endif /* PCF50606_H */ diff --git a/firmware/powermgmt.c b/firmware/powermgmt.c index ca68fb168a..50b734bbbd 100644 --- a/firmware/powermgmt.c +++ b/firmware/powermgmt.c @@ -59,10 +59,8 @@ #include #endif -#ifdef IAUDIO_X5 -#ifndef SIMULATOR -extern void pcf50606_reset_timeout(void); -#endif +#if defined(IAUDIO_X5) && !defined (SIMULATOR) +#include "pcf50606.h" #endif /* @@ -1033,12 +1031,10 @@ void cancel_shutdown(void) { logf("sys_cancel_shutdown()"); -#ifdef IAUDIO_X5 -#ifndef SIMULATOR +#if defined(IAUDIO_X5) && !defined (SIMULATOR) /* TODO: Move some things to target/ tree */ if (shutdown_timeout) pcf50606_reset_timeout(); -#endif #endif shutdown_timeout = 0; @@ -1076,10 +1072,8 @@ void shutdown_hw(void) backlight_set_fade_out(0); #endif backlight_off(); -#endif /* IAUDIO_X5 */ -#ifndef IAUDIO_X5 lcd_set_contrast(0); -#endif +#endif /* IAUDIO_X5 */ #ifdef HAVE_REMOTE_LCD remote_backlight_off(); lcd_remote_set_contrast(0); diff --git a/firmware/target/coldfire/iaudio/x5/pcf50606-x5.c b/firmware/target/coldfire/iaudio/x5/pcf50606-x5.c index 59ecdb612c..58ff5d5cb0 100644 --- a/firmware/target/coldfire/iaudio/x5/pcf50606-x5.c +++ b/firmware/target/coldfire/iaudio/x5/pcf50606-x5.c @@ -17,515 +17,11 @@ * ****************************************************************************/ #include "config.h" -#include "cpu.h" -#include -#include "kernel.h" #include "system.h" -#include "hwcompat.h" -#include "logf.h" -#include "debug.h" -#include "string.h" -#include "generic_i2c.h" +#include "kernel.h" +#include "pcf50606.h" #include "powermgmt.h" -#define USE_ASM - -/* Data */ -#define SDA_BITNUM 12 /* SDA1/RXD1/GPIO44 */ -#define SDA_GPIO_READ GPIO1_READ /* MBAR2 + 0x0b0 */ -#define SDA_GPIO_OUT GPIO1_OUT /* MBAR2 + 0x0b4 */ -#define SDA_GPIO_ENABLE GPIO1_ENABLE /* MBAR2 + 0x0b8 */ -#define SDA_GPIO_FUNCTION GPIO1_FUNCTION /* MBAR2 + 0x0bc */ - -/* Clock */ -#define SCL_BITNUM 10 /* SCL1/TXD1/GPIO10 */ -#define SCL_GPIO_READ GPIO_READ /* MBAR2 + 0x000 */ -#define SCL_GPIO_OUT GPIO_OUT /* MBAR2 + 0x004 */ -#define SCL_GPIO_ENABLE GPIO_ENABLE /* MBAR2 + 0x008 */ -#define SCL_GPIO_FUNCTION GPIO_FUNCTION /* MBAR2 + 0x00c */ - -#define PCF50606_ADDR 0x10 -#define SCL_BIT (1ul << SCL_BITNUM) -#define SDA_BIT (1ul << SDA_BITNUM) - -#define SDA ( SDA_BIT & SDA_GPIO_READ) -#define SDA_LO_OUT or_l( SDA_BIT, &SDA_GPIO_ENABLE) -#define SDA_HI_IN and_l(~SDA_BIT, &SDA_GPIO_ENABLE) - -#define SCL ( SCL_BIT & SCL_GPIO_READ) -#define SCL_LO_OUT or_l( SCL_BIT, &SCL_GPIO_ENABLE) -#define SCL_HI_IN and_l(~SCL_BIT, &SCL_GPIO_ENABLE); while(!SCL); - -#define DELAY \ - asm ( \ - "move.l %[dly],%%d0 \n" \ - "1: \n" \ - "subq.l #1,%%d0 \n" \ - "bhi.s 1b \n" \ - : : [dly]"d"(i2c_delay) : "d0" ); - -static int i2c_delay IDATA_ATTR = 44; - -void pcf50606_i2c_recalc_delay(int cpu_clock) -{ - i2c_delay = MAX(cpu_clock / (400000*2*3) - 7, 1); -} - -inline void pcf50606_i2c_start(void) -{ -#ifdef USE_ASM - asm ( - "not.l %[sdab] \n" /* SDA_HI_IN */ - "and.l %[sdab],(8,%[sdard]) \n" - "not.l %[sdab] \n" - - "not.l %[sclb] \n" /* SCL_HI_IN */ - "and.l %[sclb],(8,%[sclrd]) \n" - "not.l %[sclb] \n" - "1: \n" - "move.l (%[sclrd]),%%d0 \n" - "btst.l %[sclbnum], %%d0 \n" - "beq.s 1b \n" - - "move.l %[dly],%%d0 \n" /* DELAY */ - "1: \n" - "subq.l #1,%%d0 \n" - "bhi.s 1b \n" - - "or.l %[sdab],(8,%[sdard]) \n" /* SDA_LO_OUT */ - - "move.l %[dly],%%d0 \n" /* DELAY */ - "1: \n" - "subq.l #1,%%d0 \n" - "bhi.s 1b \n" - - "or.l %[sclb],(8,%[sclrd]) \n" /* SCL_LO_OUT */ - : /* outputs */ - : /* inputs */ - [sclrd] "a"(&SCL_GPIO_READ), - [sclb] "d"(SCL_BIT), - [sclbnum] "i"(SCL_BITNUM), - [sdard] "a"(&SDA_GPIO_READ), - [sdab] "d"(SDA_BIT), - [dly] "d"(i2c_delay) - : /* clobbers */ - "d0" - ); -#else - SDA_HI_IN; - SCL_HI_IN; - DELAY; - SDA_LO_OUT; - DELAY; - SCL_LO_OUT; -#endif -} - -inline void pcf50606_i2c_stop(void) -{ -#ifdef USE_ASM - asm ( - "or.l %[sdab],(8,%[sdard]) \n" /* SDA_LO_OUT */ - - "not.l %[sclb] \n" /* SCL_HI_IN */ - "and.l %[sclb],(8,%[sclrd]) \n" - "not.l %[sclb] \n" - "1: \n" - "move.l (%[sclrd]),%%d0 \n" - "btst.l %[sclbnum],%%d0 \n" - "beq.s 1b \n" - - "move.l %[dly],%%d0 \n" /* DELAY */ - "1: \n" - "subq.l #1,%%d0 \n" - "bhi.s 1b \n" - - "not.l %[sdab] \n" /* SDA_HI_IN */ - "and.l %[sdab],(8,%[sdard]) \n" - "not.l %[sdab] \n" - : /* outputs */ - : /* inputs */ - [sclrd] "a"(&SCL_GPIO_READ), - [sclb] "d"(SCL_BIT), - [sclbnum] "i"(SCL_BITNUM), - [sdard] "a"(&SDA_GPIO_READ), - [sdab] "d"(SDA_BIT), - [dly] "d"(i2c_delay) - : /* clobbers */ - "d0" - ); -#else - SDA_LO_OUT; - SCL_HI_IN; - DELAY; - SDA_HI_IN; -#endif -} - -inline void pcf50606_i2c_ack(bool ack) -{ -#ifdef USE_ASM - asm ( - "tst.b %[ack] \n" /* if (!ack) */ - "bne.s 1f \n" - - "not.l %[sdab] \n" /* SDA_HI_IN */ - "and.l %[sdab],(8,%[sdard]) \n" - "not.l %[sdab] \n" - ".word 0x51fb \n" /* trapf.l : else */ - "1: \n" - "or.l %[sdab],(8,%[sdard]) \n" /* SDA_LO_OUT */ - - "not.l %[sclb] \n" /* SCL_HI_IN */ - "and.l %[sclb],(8,%[sclrd]) \n" - "not.l %[sclb] \n" - "1: \n" - "move.l (%[sclrd]),%%d0 \n" - "btst.l %[sclbnum],%%d0 \n" - "beq.s 1b \n" - - "move.l %[dly],%%d0 \n" /* DELAY */ - "1: \n" - "subq.l #1,%%d0 \n" - "bhi.s 1b \n" - - "or.l %[sclb],(8,%[sclrd]) \n" /* SCL_LO_OUT */ - : /* outputs */ - : /* inputs */ - [sclrd] "a"(&SCL_GPIO_READ), - [sclb] "d"(SCL_BIT), - [sclbnum] "i"(SCL_BITNUM), - [sdard] "a"(&SDA_GPIO_READ), - [sdab] "d"(SDA_BIT), - [dly] "d"(i2c_delay), - [ack] "d"(ack) - : /* clobbers */ - "d0" - ); -#else - if(ack) - SDA_LO_OUT; - else - SDA_HI_IN; - - SCL_HI_IN; - - DELAY; - SCL_LO_OUT; -#endif -} - -inline bool pcf50606_i2c_getack(void) -{ - bool ret; - -#ifdef USE_ASM - asm ( - "not.l %[sdab] \n" /* SDA_HI_IN */ - "and.l %[sdab],(8,%[sdard]) \n" - "not.l %[sdab] \n" - - "move.l %[dly],%%d0 \n" /* DELAY */ - "1: \n" - "subq.l #1,%%d0 \n" - "bhi.s 1b \n" - - "not.l %[sclb] \n" /* SCL_HI_IN */ - "and.l %[sclb],(8,%[sclrd]) \n" - "not.l %[sclb] \n" - "1: \n" - "move.l (%[sclrd]),%%d0 \n" - "btst.l %[sclbnum],%%d0 \n" - "beq.s 1b \n" - - "move.l (%[sdard]),%%d0 \n" /* ret = !SDA */ - "btst.l %[sdabnum],%%d0 \n" - "seq.b %[ret] \n" - - "or.l %[sclb],(8,%[sclrd]) \n" /* SCL_LO_OUT */ - - "move.l %[dly],%%d0 \n" /* DELAY */ - "1: \n" - "subq.l #1,%%d0 \n" - "bhi.s 1b \n" - : /* outputs */ - [ret] "=&d"(ret) - : /* inputs */ - [sclrd] "a"(&SCL_GPIO_READ), - [sclb] "d"(SCL_BIT), - [sclbnum] "i"(SCL_BITNUM), - [sdard] "a"(&SDA_GPIO_READ), - [sdab] "d"(SDA_BIT), - [sdabnum] "i"(SDA_BITNUM), - [dly] "d"(i2c_delay) - : /* clobbers */ - "d0" - ); -#else - SDA_HI_IN; - DELAY; - SCL_HI_IN; - - ret = !SDA; - - SCL_LO_OUT; - DELAY; -#endif - return ret; -} - -void pcf50606_i2c_outb(unsigned char byte) -{ -#ifdef USE_ASM - asm volatile ( - "moveq.l #24,%%d0 \n" /* byte <<= 24 */ - "lsl.l %%d0,%[byte] \n" - "moveq.l #8,%%d1 \n" /* i = 8 */ - - "2: \n" /* do */ - "lsl.l #1,%[byte] \n" /* if ((byte <<= 1) carry) */ - "bcc.s 1f \n" - - "not.l %[sdab] \n" /* SDA_HI_IN */ - "and.l %[sdab],(8,%[sdard]) \n" - "not.l %[sdab] \n" - ".word 0x51fb \n" /* trapf.l; else */ - "1: \n" - "or.l %[sdab],(8,%[sdard]) \n" /* SDA_LO_OUT */ - - "move.l %[dly],%%d0 \n" /* DELAY */ - "1: \n" - "subq.l #1,%%d0 \n" - "bhi.s 1b \n" - - "not.l %[sclb] \n" /* SCL_HI_IN */ - "and.l %[sclb],(8,%[sclrd]) \n" - "not.l %[sclb] \n" - "1: \n" - "move.l (%[sclrd]),%%d0 \n" - "btst.l %[sclbnum],%%d0 \n" - "beq.s 1b \n" - - "move.l %[dly],%%d0 \n" /* DELAY */ - "1: \n" - "subq.l #1,%%d0 \n" - "bhi.s 1b \n" - - "or.l %[sclb],(8,%[sclrd]) \n" /* SCL_LO_OUT */ - - "subq.l #1,%%d1 \n" /* i-- */ - "bne.s 2b \n" /* while (i != 0) */ - : /* outputs */ - [byte] "+d"(byte) - : /* inputs */ - [sclrd] "a"(&SCL_GPIO_READ), - [sclb] "d"(SCL_BIT), - [sclbnum] "i"(SCL_BITNUM), - [sdard] "a"(&SDA_GPIO_READ), - [sdab] "d"(SDA_BIT), - [dly] "d"(i2c_delay) - : /* clobbers */ - "d0", "d1" - ); -#else - int i; - - /* clock out each bit, MSB first */ - for ( i=0x80; i; i>>=1 ) - { - if ( i & byte ) - SDA_HI_IN; - else - SDA_LO_OUT; - DELAY; - SCL_HI_IN; - DELAY; - SCL_LO_OUT; - } -#endif -} - -unsigned char pcf50606_i2c_inb(bool ack) -{ - unsigned char byte = 0; - -#ifdef USE_ASM - asm ( - "not.l %[sdab] \n" /* SDA_HI_IN */ - "and.l %[sdab],(8,%[sdard]) \n" - "not.l %[sdab] \n" - - "moveq.l #8,%%d1 \n" /* i = 8 */ - "clr.l %[byte] \n" /* byte = 0 */ - - "2: \n" /* do */ - "not.l %[sclb] \n" /* SCL_HI_IN */ - "and.l %[sclb],(8,%[sclrd]) \n" - "not.l %[sclb] \n" - "1: \n" - "move.l (%[sclrd]),%%d0 \n" - "btst.l %[sclbnum],%%d0 \n" - "beq.s 1b \n" - - "move.l %[dly],%%d0 \n" /* DELAY */ - "1: \n" - "subq.l #1,%%d0 \n" - "bhi.s 1b \n" - - "lsl.l #1,%[byte] \n" /* byte <<= 1 */ - "move.l (%[sdard]),%%d0 \n" /* if (SDA) */ - "btst.l %[sdabnum],%%d0 \n" - "beq.s 1f \n" - "addq.l #1,%[byte] \n" /* byte++ */ - "1: \n" - - "or.l %[sclb],(8,%[sclrd]) \n" /* SCL_LO_OUT */ - - "move.l %[dly],%%d0 \n" /* DELAY */ - "1: \n" - "subq.l #1,%%d0 \n" - "bhi.s 1b \n" - - "subq.l #1,%%d1 \n" /* i-- */ - "bne.s 2b \n" /* while (i != 0) */ - : /* outputs */ - [byte] "=&d"(byte) - : /* inputs */ - [sclrd] "a"(&SCL_GPIO_READ), - [sclb] "d"(SCL_BIT), - [sclbnum] "i"(SCL_BITNUM), - [sdard] "a"(&SDA_GPIO_READ), - [sdab] "d"(SDA_BIT), - [sdabnum] "i"(SDA_BITNUM), - [dly] "d"(i2c_delay) - : /* clobbers */ - "d0", "d1" - ); -#else - int i; - - /* clock in each bit, MSB first */ - SDA_HI_IN; - for ( i=0x80; i; i>>=1 ) - { - SCL_HI_IN; - DELAY; - if ( SDA ) - byte |= i; - SCL_LO_OUT; - DELAY; - } -#endif - - pcf50606_i2c_ack(ack); - - return byte; -} - -int pcf50606_i2c_write(int address, const unsigned char* buf, int count) -{ - int i,x=0; - - pcf50606_i2c_start(); - pcf50606_i2c_outb(address & 0xfe); - if (pcf50606_i2c_getack()) - { - for (i=0; i= 0) - { - pcf50606_i2c_start(); - pcf50606_i2c_outb(0x11); - if (pcf50606_i2c_getack()) - { - for(i = 0;i < count-1;i++) - buf[i] = pcf50606_i2c_inb(true); - - buf[i] = pcf50606_i2c_inb(false); - } - else - { - ret = -1; - } - } - - pcf50606_i2c_stop(); - - return ret; -} - -int pcf50606_read(int address) -{ - int ret; - unsigned char c; - - ret = pcf50606_read_multiple(address, &c, 1); - if(ret >= 0) - return c; - else - return ret; -} - -int pcf50606_write_multiple(int address, const unsigned char* buf, int count) -{ - unsigned char obuf[1]; - int i; - int ret = 0; - - obuf[0] = address; - - /* send write command */ - if (pcf50606_i2c_write(PCF50606_ADDR, obuf, 1) >= 0) - { - for (i=0; i ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2005 by Linus Nielsen Feltzing + * + * 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 "config.h" +#include "system.h" +#include "kernel.h" +#include "pcf50606.h" + +/* These voltages were determined by measuring the output of the PCF50606 + on a running H300, and verified by disassembling the original firmware */ +static void set_voltages(void) +{ + static const unsigned char buf[5] = + { + 0xf4, /* IOREGC = 2.9V, ON in all states */ + 0xef, /* D1REGC = 2.4V, ON in all states */ + 0x18, /* D2REGC = 3.3V, OFF in all states */ + 0xf0, /* D3REGC = 2.5V, ON in all states */ + 0xef, /* LPREGC1 = 2.4V, ON in all states */ + }; + + pcf50606_write_multiple(0x23, buf, 5); +} + +void pcf50606_init(void) +{ + pcf50606_i2c_init(); + + set_voltages(); + + pcf50606_write(0x08, 0x60); /* Wake on USB and charger insertion */ + pcf50606_write(0x09, 0x05); /* USB and ON key debounce: 14ms */ + pcf50606_write(0x29, 0x1C); /* Disable the unused MBC module */ + + pcf50606_write(0x35, 0x13); /* Backlight PWM = 512Hz 50/50 */ + pcf50606_write(0x3a, 0x3b); /* PWM output on GPOOD1 */ +} diff --git a/firmware/target/coldfire/pcf50606-coldfire.c b/firmware/target/coldfire/pcf50606-coldfire.c new file mode 100644 index 0000000000..ecc9e0ee72 --- /dev/null +++ b/firmware/target/coldfire/pcf50606-coldfire.c @@ -0,0 +1,540 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2006 by Linus Nielsen Feltzing + * + * 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 "config.h" +#include "system.h" +#include "logf.h" +#include "kernel.h" +#include "pcf50606.h" + +#define USE_ASM + +/* Define the approprate bits for SDA and SCL being the only difference in + config between each player. */ +#if defined(IRIVER_H300_SERIES) +#define SDA_BITNUM 13 /* LRCK3/GPIO45 */ +#define SCL_BITNUM 12 /* SWE/GPIO12 */ +#elif defined(IAUDIO_X5) +#define SDA_BITNUM 12 /* SDA1/RXD1/GPIO44 */ +#define SCL_BITNUM 10 /* SCL1/TXD1/GPIO10 */ +#endif + +/* Data */ +#define SDA_GPIO_READ GPIO1_READ /* MBAR2 + 0x0b0 */ +#define SDA_GPIO_OUT GPIO1_OUT /* MBAR2 + 0x0b4 */ +#define SDA_GPIO_ENABLE GPIO1_ENABLE /* MBAR2 + 0x0b8 */ +#define SDA_GPIO_FUNCTION GPIO1_FUNCTION /* MBAR2 + 0x0bc */ + +/* Clock */ +#define SCL_GPIO_READ GPIO_READ /* MBAR2 + 0x000 */ +#define SCL_GPIO_OUT GPIO_OUT /* MBAR2 + 0x004 */ +#define SCL_GPIO_ENABLE GPIO_ENABLE /* MBAR2 + 0x008 */ +#define SCL_GPIO_FUNCTION GPIO_FUNCTION /* MBAR2 + 0x00c */ + +#define PCF50606_ADDR 0x10 +#define SCL_BIT (1ul << SCL_BITNUM) +#define SDA_BIT (1ul << SDA_BITNUM) + +#define SDA ( SDA_BIT & SDA_GPIO_READ) +#define SDA_LO_OUT or_l( SDA_BIT, &SDA_GPIO_ENABLE) +#define SDA_HI_IN and_l(~SDA_BIT, &SDA_GPIO_ENABLE) + +#define SCL ( SCL_BIT & SCL_GPIO_READ) +#define SCL_LO_OUT or_l( SCL_BIT, &SCL_GPIO_ENABLE) +#define SCL_HI_IN and_l(~SCL_BIT, &SCL_GPIO_ENABLE); while(!SCL); + +#define DELAY \ + asm ( \ + "move.l %[dly],%%d0 \n" \ + "1: \n" \ + "subq.l #1,%%d0 \n" \ + "bhi.s 1b \n" \ + : : [dly]"d"(i2c_delay) : "d0" ); + +void pcf50606_i2c_init(void) +{ + /* Bit banged I2C */ + or_l(SDA_BIT, &SDA_GPIO_FUNCTION); + or_l(SCL_BIT, &SCL_GPIO_FUNCTION); + and_l(~SDA_BIT, &SDA_GPIO_OUT); + and_l(~SCL_BIT, &SCL_GPIO_OUT); + and_l(~SDA_BIT, &SDA_GPIO_ENABLE); + and_l(~SCL_BIT, &SCL_GPIO_ENABLE); +} + +static int i2c_delay IDATA_ATTR = 44; + +void pcf50606_i2c_recalc_delay(int cpu_clock) +{ + i2c_delay = MAX(cpu_clock / (400000*2*3) - 7, 1); +} + +inline void pcf50606_i2c_start(void) +{ +#ifdef USE_ASM + asm ( + "not.l %[sdab] \n" /* SDA_HI_IN */ + "and.l %[sdab],(8,%[sdard]) \n" + "not.l %[sdab] \n" + + "not.l %[sclb] \n" /* SCL_HI_IN */ + "and.l %[sclb],(8,%[sclrd]) \n" + "not.l %[sclb] \n" + "1: \n" + "move.l (%[sclrd]),%%d0 \n" + "btst.l %[sclbnum], %%d0 \n" + "beq.s 1b \n" + + "move.l %[dly],%%d0 \n" /* DELAY */ + "1: \n" + "subq.l #1,%%d0 \n" + "bhi.s 1b \n" + + "or.l %[sdab],(8,%[sdard]) \n" /* SDA_LO_OUT */ + + "move.l %[dly],%%d0 \n" /* DELAY */ + "1: \n" + "subq.l #1,%%d0 \n" + "bhi.s 1b \n" + + "or.l %[sclb],(8,%[sclrd]) \n" /* SCL_LO_OUT */ + : /* outputs */ + : /* inputs */ + [sclrd] "a"(&SCL_GPIO_READ), + [sclb] "d"(SCL_BIT), + [sclbnum] "i"(SCL_BITNUM), + [sdard] "a"(&SDA_GPIO_READ), + [sdab] "d"(SDA_BIT), + [dly] "d"(i2c_delay) + : /* clobbers */ + "d0" + ); +#else + SDA_HI_IN; + SCL_HI_IN; + DELAY; + SDA_LO_OUT; + DELAY; + SCL_LO_OUT; +#endif +} + +inline void pcf50606_i2c_stop(void) +{ +#ifdef USE_ASM + asm ( + "or.l %[sdab],(8,%[sdard]) \n" /* SDA_LO_OUT */ + + "not.l %[sclb] \n" /* SCL_HI_IN */ + "and.l %[sclb],(8,%[sclrd]) \n" + "not.l %[sclb] \n" + "1: \n" + "move.l (%[sclrd]),%%d0 \n" + "btst.l %[sclbnum],%%d0 \n" + "beq.s 1b \n" + + "move.l %[dly],%%d0 \n" /* DELAY */ + "1: \n" + "subq.l #1,%%d0 \n" + "bhi.s 1b \n" + + "not.l %[sdab] \n" /* SDA_HI_IN */ + "and.l %[sdab],(8,%[sdard]) \n" + "not.l %[sdab] \n" + : /* outputs */ + : /* inputs */ + [sclrd] "a"(&SCL_GPIO_READ), + [sclb] "d"(SCL_BIT), + [sclbnum] "i"(SCL_BITNUM), + [sdard] "a"(&SDA_GPIO_READ), + [sdab] "d"(SDA_BIT), + [dly] "d"(i2c_delay) + : /* clobbers */ + "d0" + ); +#else + SDA_LO_OUT; + SCL_HI_IN; + DELAY; + SDA_HI_IN; +#endif +} + +inline void pcf50606_i2c_ack(bool ack) +{ +#ifdef USE_ASM + asm ( + "tst.b %[ack] \n" /* if (!ack) */ + "bne.s 1f \n" + + "not.l %[sdab] \n" /* SDA_HI_IN */ + "and.l %[sdab],(8,%[sdard]) \n" + "not.l %[sdab] \n" + ".word 0x51fb \n" /* trapf.l : else */ + "1: \n" + "or.l %[sdab],(8,%[sdard]) \n" /* SDA_LO_OUT */ + + "not.l %[sclb] \n" /* SCL_HI_IN */ + "and.l %[sclb],(8,%[sclrd]) \n" + "not.l %[sclb] \n" + "1: \n" + "move.l (%[sclrd]),%%d0 \n" + "btst.l %[sclbnum],%%d0 \n" + "beq.s 1b \n" + + "move.l %[dly],%%d0 \n" /* DELAY */ + "1: \n" + "subq.l #1,%%d0 \n" + "bhi.s 1b \n" + + "or.l %[sclb],(8,%[sclrd]) \n" /* SCL_LO_OUT */ + : /* outputs */ + : /* inputs */ + [sclrd] "a"(&SCL_GPIO_READ), + [sclb] "d"(SCL_BIT), + [sclbnum] "i"(SCL_BITNUM), + [sdard] "a"(&SDA_GPIO_READ), + [sdab] "d"(SDA_BIT), + [dly] "d"(i2c_delay), + [ack] "d"(ack) + : /* clobbers */ + "d0" + ); +#else + if(ack) + SDA_LO_OUT; + else + SDA_HI_IN; + + SCL_HI_IN; + + DELAY; + SCL_LO_OUT; +#endif +} + +inline bool pcf50606_i2c_getack(void) +{ + bool ret; + +#ifdef USE_ASM + asm ( + "not.l %[sdab] \n" /* SDA_HI_IN */ + "and.l %[sdab],(8,%[sdard]) \n" + "not.l %[sdab] \n" + + "move.l %[dly],%%d0 \n" /* DELAY */ + "1: \n" + "subq.l #1,%%d0 \n" + "bhi.s 1b \n" + + "not.l %[sclb] \n" /* SCL_HI_IN */ + "and.l %[sclb],(8,%[sclrd]) \n" + "not.l %[sclb] \n" + "1: \n" + "move.l (%[sclrd]),%%d0 \n" + "btst.l %[sclbnum],%%d0 \n" + "beq.s 1b \n" + + "move.l (%[sdard]),%%d0 \n" /* ret = !SDA */ + "btst.l %[sdabnum],%%d0 \n" + "seq.b %[ret] \n" + + "or.l %[sclb],(8,%[sclrd]) \n" /* SCL_LO_OUT */ + + "move.l %[dly],%%d0 \n" /* DELAY */ + "1: \n" + "subq.l #1,%%d0 \n" + "bhi.s 1b \n" + : /* outputs */ + [ret] "=&d"(ret) + : /* inputs */ + [sclrd] "a"(&SCL_GPIO_READ), + [sclb] "d"(SCL_BIT), + [sclbnum] "i"(SCL_BITNUM), + [sdard] "a"(&SDA_GPIO_READ), + [sdab] "d"(SDA_BIT), + [sdabnum] "i"(SDA_BITNUM), + [dly] "d"(i2c_delay) + : /* clobbers */ + "d0" + ); +#else + SDA_HI_IN; + DELAY; + SCL_HI_IN; + + ret = !SDA; + + SCL_LO_OUT; + DELAY; +#endif + return ret; +} + +void pcf50606_i2c_outb(unsigned char byte) +{ +#ifdef USE_ASM + asm volatile ( + "moveq.l #24,%%d0 \n" /* byte <<= 24 */ + "lsl.l %%d0,%[byte] \n" + "moveq.l #8,%%d1 \n" /* i = 8 */ + + "2: \n" /* do */ + "lsl.l #1,%[byte] \n" /* if ((byte <<= 1) carry) */ + "bcc.s 1f \n" + + "not.l %[sdab] \n" /* SDA_HI_IN */ + "and.l %[sdab],(8,%[sdard]) \n" + "not.l %[sdab] \n" + ".word 0x51fb \n" /* trapf.l; else */ + "1: \n" + "or.l %[sdab],(8,%[sdard]) \n" /* SDA_LO_OUT */ + + "move.l %[dly],%%d0 \n" /* DELAY */ + "1: \n" + "subq.l #1,%%d0 \n" + "bhi.s 1b \n" + + "not.l %[sclb] \n" /* SCL_HI_IN */ + "and.l %[sclb],(8,%[sclrd]) \n" + "not.l %[sclb] \n" + "1: \n" + "move.l (%[sclrd]),%%d0 \n" + "btst.l %[sclbnum],%%d0 \n" + "beq.s 1b \n" + + "move.l %[dly],%%d0 \n" /* DELAY */ + "1: \n" + "subq.l #1,%%d0 \n" + "bhi.s 1b \n" + + "or.l %[sclb],(8,%[sclrd]) \n" /* SCL_LO_OUT */ + + "subq.l #1,%%d1 \n" /* i-- */ + "bne.s 2b \n" /* while (i != 0) */ + : /* outputs */ + [byte] "+d"(byte) + : /* inputs */ + [sclrd] "a"(&SCL_GPIO_READ), + [sclb] "d"(SCL_BIT), + [sclbnum] "i"(SCL_BITNUM), + [sdard] "a"(&SDA_GPIO_READ), + [sdab] "d"(SDA_BIT), + [dly] "d"(i2c_delay) + : /* clobbers */ + "d0", "d1" + ); +#else + int i; + + /* clock out each bit, MSB first */ + for ( i=0x80; i; i>>=1 ) + { + if ( i & byte ) + SDA_HI_IN; + else + SDA_LO_OUT; + DELAY; + SCL_HI_IN; + DELAY; + SCL_LO_OUT; + } +#endif +} + +unsigned char pcf50606_i2c_inb(bool ack) +{ + unsigned char byte = 0; + +#ifdef USE_ASM + asm ( + "not.l %[sdab] \n" /* SDA_HI_IN */ + "and.l %[sdab],(8,%[sdard]) \n" + "not.l %[sdab] \n" + + "moveq.l #8,%%d1 \n" /* i = 8 */ + "clr.l %[byte] \n" /* byte = 0 */ + + "2: \n" /* do */ + "not.l %[sclb] \n" /* SCL_HI_IN */ + "and.l %[sclb],(8,%[sclrd]) \n" + "not.l %[sclb] \n" + "1: \n" + "move.l (%[sclrd]),%%d0 \n" + "btst.l %[sclbnum],%%d0 \n" + "beq.s 1b \n" + + "move.l %[dly],%%d0 \n" /* DELAY */ + "1: \n" + "subq.l #1,%%d0 \n" + "bhi.s 1b \n" + + "lsl.l #1,%[byte] \n" /* byte <<= 1 */ + "move.l (%[sdard]),%%d0 \n" /* if (SDA) */ + "btst.l %[sdabnum],%%d0 \n" + "beq.s 1f \n" + "addq.l #1,%[byte] \n" /* byte++ */ + "1: \n" + + "or.l %[sclb],(8,%[sclrd]) \n" /* SCL_LO_OUT */ + + "move.l %[dly],%%d0 \n" /* DELAY */ + "1: \n" + "subq.l #1,%%d0 \n" + "bhi.s 1b \n" + + "subq.l #1,%%d1 \n" /* i-- */ + "bne.s 2b \n" /* while (i != 0) */ + : /* outputs */ + [byte] "=&d"(byte) + : /* inputs */ + [sclrd] "a"(&SCL_GPIO_READ), + [sclb] "d"(SCL_BIT), + [sclbnum] "i"(SCL_BITNUM), + [sdard] "a"(&SDA_GPIO_READ), + [sdab] "d"(SDA_BIT), + [sdabnum] "i"(SDA_BITNUM), + [dly] "d"(i2c_delay) + : /* clobbers */ + "d0", "d1" + ); +#else + int i; + + /* clock in each bit, MSB first */ + SDA_HI_IN; + for ( i=0x80; i; i>>=1 ) + { + SCL_HI_IN; + DELAY; + if ( SDA ) + byte |= i; + SCL_LO_OUT; + DELAY; + } +#endif + + pcf50606_i2c_ack(ack); + + return byte; +} + +int pcf50606_i2c_write(int address, const unsigned char* buf, int count) +{ + int i,x=0; + + pcf50606_i2c_start(); + pcf50606_i2c_outb(address & 0xfe); + if (pcf50606_i2c_getack()) + { + for (i=0; i= 0) + { + pcf50606_i2c_start(); + pcf50606_i2c_outb(0x11); + if (pcf50606_i2c_getack()) + { + for(i = 0;i < count-1;i++) + buf[i] = pcf50606_i2c_inb(true); + + buf[i] = pcf50606_i2c_inb(false); + } + else + { + ret = -1; + } + } + + pcf50606_i2c_stop(); + + return ret; +} + +int pcf50606_read(int address) +{ + int ret; + unsigned char c; + + ret = pcf50606_read_multiple(address, &c, 1); + if(ret >= 0) + return c; + else + return ret; +} + +int pcf50606_write_multiple(int address, const unsigned char* buf, int count) +{ + unsigned char obuf[1]; + int i; + int ret = 0; + + obuf[0] = address; + + /* send write command */ + if (pcf50606_i2c_write(PCF50606_ADDR, obuf, 1) >= 0) + { + for (i=0; i