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/target/coldfire/pcf50606-coldfire.c | 540 +++++++++++++++++++++++++++ 1 file changed, 540 insertions(+) create mode 100644 firmware/target/coldfire/pcf50606-coldfire.c (limited to 'firmware/target/coldfire/pcf50606-coldfire.c') 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