diff options
Diffstat (limited to 'cpu/ppc4xx/i2c.c')
-rw-r--r-- | cpu/ppc4xx/i2c.c | 401 |
1 files changed, 200 insertions, 201 deletions
diff --git a/cpu/ppc4xx/i2c.c b/cpu/ppc4xx/i2c.c index 4bf0bbd..099d30a 100644 --- a/cpu/ppc4xx/i2c.c +++ b/cpu/ppc4xx/i2c.c @@ -85,7 +85,7 @@ void i2c_init (int speed, int slaveadd) unsigned long freqOPB; int val, divisor; -#ifdef CFG_I2C_INIT_BOARD +#ifdef CFG_I2C_INIT_BOARD /* call board specific i2c bus reset routine before accessing the */ /* environment, which might be in a chip on that bus. For details */ /* about this problem see doc/I2C_Edge_Conditions. */ @@ -134,19 +134,19 @@ void i2c_init (int speed, int slaveadd) __asm__ volatile ("eieio"); - val = in8(IIC_MDCNTL); - __asm__ volatile ("eieio"); + val = in8(IIC_MDCNTL); + __asm__ volatile ("eieio"); - /* Ignore General Call, slave transfers are ignored, - disable interrupts, exit unknown bus state, enable hold - SCL - 100kHz normaly or FastMode for 400kHz and above - */ + /* Ignore General Call, slave transfers are ignored, + disable interrupts, exit unknown bus state, enable hold + SCL + 100kHz normaly or FastMode for 400kHz and above + */ - val |= IIC_MDCNTL_EUBS|IIC_MDCNTL_HSCL; - if( speed >= 400000 ){ - val |= IIC_MDCNTL_FSM; - } + val |= IIC_MDCNTL_EUBS|IIC_MDCNTL_HSCL; + if( speed >= 400000 ){ + val |= IIC_MDCNTL_FSM; + } out8 (IIC_MDCNTL, val); /* clear control reg */ @@ -182,153 +182,153 @@ void i2c_init (int speed, int slaveadd) */ static int i2c_transfer(unsigned char cmd_type, - unsigned char chip, - unsigned char addr[], - unsigned char addr_len, - unsigned char data[], + unsigned char chip, + unsigned char addr[], + unsigned char addr_len, + unsigned char data[], unsigned short data_len ) { - unsigned char* ptr; - int reading; - int tran,cnt; - int result; - int status; - int i; - uchar creg; - - if( data == 0 || data_len == 0 ){ - /*Don't support data transfer of no length or to address 0*/ - printf( "i2c_transfer: bad call\n" ); - return IIC_NOK; - } - if( addr && addr_len ){ - ptr = addr; - cnt = addr_len; - reading = 0; - }else{ - ptr = data; - cnt = data_len; - reading = cmd_type; - } - - /*Clear Stop Complete Bit*/ - out8(IIC_STS,IIC_STS_SCMP); - /* Check init */ - i=10; - do { - /* Get status */ - status = in8(IIC_STS); - __asm__ volatile("eieio"); - i--; - } while ((status & IIC_STS_PT) && (i>0)); - - if (status & IIC_STS_PT) { - result = IIC_NOK_TOUT; - return(result); - } - /*flush the Master/Slave Databuffers*/ - out8(IIC_MDCNTL, ((in8(IIC_MDCNTL))|IIC_MDCNTL_FMDB|IIC_MDCNTL_FSDB)); - /*need to wait 4 OPB clocks? code below should take that long*/ - - /* 7-bit adressing */ - out8(IIC_HMADR,0); - out8(IIC_LMADR, chip); - __asm__ volatile("eieio"); - - tran = 0; - result = IIC_OK; - creg = 0; - - while ( tran != cnt && (result == IIC_OK)) { - int bc,j; - - /* Control register = - Normal transfer, 7-bits adressing, Transfer up to bc bytes, Normal start, - Transfer is a sequence of transfers - */ - creg |= IIC_CNTL_PT; - - bc = (cnt - tran) > 4 ? 4 : - cnt - tran; - creg |= (bc-1)<<4; - /* if the real cmd type is write continue trans*/ - if ( (!cmd_type && (ptr == addr)) || ((tran+bc) != cnt) ) - creg |= IIC_CNTL_CHT; - - if (reading) - creg |= IIC_CNTL_READ; - else { - for(j=0; j<bc; j++) { - /* Set buffer */ - out8(IIC_MDBUF,ptr[tran+j]); - __asm__ volatile("eieio"); - } - } - out8(IIC_CNTL, creg ); - __asm__ volatile("eieio"); - - /* Transfer is in progress - we have to wait for upto 5 bytes of data - 1 byte chip address+r/w bit then bc bytes - of data. - udelay(10) is 1 bit time at 100khz - Doubled for slop. 20 is too small. + unsigned char* ptr; + int reading; + int tran,cnt; + int result; + int status; + int i; + uchar creg; + + if( data == 0 || data_len == 0 ){ + /*Don't support data transfer of no length or to address 0*/ + printf( "i2c_transfer: bad call\n" ); + return IIC_NOK; + } + if( addr && addr_len ){ + ptr = addr; + cnt = addr_len; + reading = 0; + }else{ + ptr = data; + cnt = data_len; + reading = cmd_type; + } + + /*Clear Stop Complete Bit*/ + out8(IIC_STS,IIC_STS_SCMP); + /* Check init */ + i=10; + do { + /* Get status */ + status = in8(IIC_STS); + __asm__ volatile("eieio"); + i--; + } while ((status & IIC_STS_PT) && (i>0)); + + if (status & IIC_STS_PT) { + result = IIC_NOK_TOUT; + return(result); + } + /*flush the Master/Slave Databuffers*/ + out8(IIC_MDCNTL, ((in8(IIC_MDCNTL))|IIC_MDCNTL_FMDB|IIC_MDCNTL_FSDB)); + /*need to wait 4 OPB clocks? code below should take that long*/ + + /* 7-bit adressing */ + out8(IIC_HMADR,0); + out8(IIC_LMADR, chip); + __asm__ volatile("eieio"); + + tran = 0; + result = IIC_OK; + creg = 0; + + while ( tran != cnt && (result == IIC_OK)) { + int bc,j; + + /* Control register = + Normal transfer, 7-bits adressing, Transfer up to bc bytes, Normal start, + Transfer is a sequence of transfers */ - i=2*5*8; - do { - /* Get status */ - status = in8(IIC_STS); - __asm__ volatile("eieio"); - udelay (10); - i--; - } while ((status & IIC_STS_PT) && !(status & IIC_STS_ERR) + creg |= IIC_CNTL_PT; + + bc = (cnt - tran) > 4 ? 4 : + cnt - tran; + creg |= (bc-1)<<4; + /* if the real cmd type is write continue trans*/ + if ( (!cmd_type && (ptr == addr)) || ((tran+bc) != cnt) ) + creg |= IIC_CNTL_CHT; + + if (reading) + creg |= IIC_CNTL_READ; + else { + for(j=0; j<bc; j++) { + /* Set buffer */ + out8(IIC_MDBUF,ptr[tran+j]); + __asm__ volatile("eieio"); + } + } + out8(IIC_CNTL, creg ); + __asm__ volatile("eieio"); + + /* Transfer is in progress + we have to wait for upto 5 bytes of data + 1 byte chip address+r/w bit then bc bytes + of data. + udelay(10) is 1 bit time at 100khz + Doubled for slop. 20 is too small. + */ + i=2*5*8; + do { + /* Get status */ + status = in8(IIC_STS); + __asm__ volatile("eieio"); + udelay (10); + i--; + } while ((status & IIC_STS_PT) && !(status & IIC_STS_ERR) && (i>0)); - if (status & IIC_STS_ERR) { - result = IIC_NOK; - status = in8 (IIC_EXTSTS); - /* Lost arbitration? */ - if (status & IIC_EXTSTS_LA) - result = IIC_NOK_LA; - /* Incomplete transfer? */ - if (status & IIC_EXTSTS_ICT) - result = IIC_NOK_ICT; - /* Transfer aborted? */ - if (status & IIC_EXTSTS_XFRA) - result = IIC_NOK_XFRA; - } else if ( status & IIC_STS_PT) { - result = IIC_NOK_TOUT; - } - /* Command is reading => get buffer */ - if ((reading) && (result == IIC_OK)) { - /* Are there data in buffer */ - if (status & IIC_STS_MDBS) { - /* - even if we have data we have to wait 4OPB clocks - for it to hit the front of the FIFO, after that - we can just read. We should check XFCNT here and - if the FIFO is full there is no need to wait. + if (status & IIC_STS_ERR) { + result = IIC_NOK; + status = in8 (IIC_EXTSTS); + /* Lost arbitration? */ + if (status & IIC_EXTSTS_LA) + result = IIC_NOK_LA; + /* Incomplete transfer? */ + if (status & IIC_EXTSTS_ICT) + result = IIC_NOK_ICT; + /* Transfer aborted? */ + if (status & IIC_EXTSTS_XFRA) + result = IIC_NOK_XFRA; + } else if ( status & IIC_STS_PT) { + result = IIC_NOK_TOUT; + } + /* Command is reading => get buffer */ + if ((reading) && (result == IIC_OK)) { + /* Are there data in buffer */ + if (status & IIC_STS_MDBS) { + /* + even if we have data we have to wait 4OPB clocks + for it to hit the front of the FIFO, after that + we can just read. We should check XFCNT here and + if the FIFO is full there is no need to wait. */ - udelay (1); - for(j=0;j<bc;j++) { - ptr[tran+j] = in8(IIC_MDBUF); - __asm__ volatile("eieio"); - } - } else - result = IIC_NOK_DATA; - } - creg = 0; - tran+=bc; - if( ptr == addr && tran == cnt ) { - ptr = data; - cnt = data_len; - tran = 0; - reading = cmd_type; - if( reading ) - creg = IIC_CNTL_RPST; - } - } - return (result); + udelay (1); + for(j=0;j<bc;j++) { + ptr[tran+j] = in8(IIC_MDBUF); + __asm__ volatile("eieio"); + } + } else + result = IIC_NOK_DATA; + } + creg = 0; + tran+=bc; + if( ptr == addr && tran == cnt ) { + ptr = data; + cnt = data_len; + tran = 0; + reading = cmd_type; + if( reading ) + creg = IIC_CNTL_RPST; + } + } + return (result); } int i2c_probe (uchar chip) @@ -337,89 +337,88 @@ int i2c_probe (uchar chip) buf[0] = 0; - /* - * What is needed is to send the chip address and verify that the - * address was <ACK>ed (i.e. there was a chip at that address which - * drove the data line low). - */ - return(i2c_transfer (1, chip << 1, 0,0, buf, 1) != 0); + /* + * What is needed is to send the chip address and verify that the + * address was <ACK>ed (i.e. there was a chip at that address which + * drove the data line low). + */ + return(i2c_transfer (1, chip << 1, 0,0, buf, 1) != 0); } - int i2c_read (uchar chip, uint addr, int alen, uchar * buffer, int len) { - uchar xaddr[4]; - int ret; + uchar xaddr[4]; + int ret; if ( alen > 4 ) { printf ("I2C read: addr len %d not supported\n", alen); return 1; } - if ( alen > 0 ) { - xaddr[0] = (addr >> 24) & 0xFF; - xaddr[1] = (addr >> 16) & 0xFF; - xaddr[2] = (addr >> 8) & 0xFF; - xaddr[3] = addr & 0xFF; - } + if ( alen > 0 ) { + xaddr[0] = (addr >> 24) & 0xFF; + xaddr[1] = (addr >> 16) & 0xFF; + xaddr[2] = (addr >> 8) & 0xFF; + xaddr[3] = addr & 0xFF; + } #ifdef CFG_I2C_EEPROM_ADDR_OVERFLOW /* - * EEPROM chips that implement "address overflow" are ones - * like Catalyst 24WC04/08/16 which has 9/10/11 bits of - * address and the extra bits end up in the "chip address" - * bit slots. This makes a 24WC08 (1Kbyte) chip look like - * four 256 byte chips. + * EEPROM chips that implement "address overflow" are ones + * like Catalyst 24WC04/08/16 which has 9/10/11 bits of + * address and the extra bits end up in the "chip address" + * bit slots. This makes a 24WC08 (1Kbyte) chip look like + * four 256 byte chips. * - * Note that we consider the length of the address field to - * still be one byte because the extra address bits are - * hidden in the chip address. + * Note that we consider the length of the address field to + * still be one byte because the extra address bits are + * hidden in the chip address. */ - if( alen > 0 ) - chip |= ((addr >> (alen * 8)) & CFG_I2C_EEPROM_ADDR_OVERFLOW); + if( alen > 0 ) + chip |= ((addr >> (alen * 8)) & CFG_I2C_EEPROM_ADDR_OVERFLOW); #endif - if( (ret = i2c_transfer( 1, chip<<1, &xaddr[4-alen], alen, buffer, len )) != 0) { - printf( "I2c read: failed %d\n", ret); - return 1; - } - return 0; + if( (ret = i2c_transfer( 1, chip<<1, &xaddr[4-alen], alen, buffer, len )) != 0) { + printf( "I2c read: failed %d\n", ret); + return 1; + } + return 0; } int i2c_write (uchar chip, uint addr, int alen, uchar * buffer, int len) { - uchar xaddr[4]; + uchar xaddr[4]; if ( alen > 4 ) { printf ("I2C write: addr len %d not supported\n", alen); return 1; } - if ( alen > 0 ) { - xaddr[0] = (addr >> 24) & 0xFF; - xaddr[1] = (addr >> 16) & 0xFF; - xaddr[2] = (addr >> 8) & 0xFF; - xaddr[3] = addr & 0xFF; - } + if ( alen > 0 ) { + xaddr[0] = (addr >> 24) & 0xFF; + xaddr[1] = (addr >> 16) & 0xFF; + xaddr[2] = (addr >> 8) & 0xFF; + xaddr[3] = addr & 0xFF; + } #ifdef CFG_I2C_EEPROM_ADDR_OVERFLOW /* - * EEPROM chips that implement "address overflow" are ones - * like Catalyst 24WC04/08/16 which has 9/10/11 bits of - * address and the extra bits end up in the "chip address" - * bit slots. This makes a 24WC08 (1Kbyte) chip look like - * four 256 byte chips. + * EEPROM chips that implement "address overflow" are ones + * like Catalyst 24WC04/08/16 which has 9/10/11 bits of + * address and the extra bits end up in the "chip address" + * bit slots. This makes a 24WC08 (1Kbyte) chip look like + * four 256 byte chips. * - * Note that we consider the length of the address field to - * still be one byte because the extra address bits are - * hidden in the chip address. + * Note that we consider the length of the address field to + * still be one byte because the extra address bits are + * hidden in the chip address. */ - if( alen > 0 ) - chip |= ((addr >> (alen * 8)) & CFG_I2C_EEPROM_ADDR_OVERFLOW); + if( alen > 0 ) + chip |= ((addr >> (alen * 8)) & CFG_I2C_EEPROM_ADDR_OVERFLOW); #endif - return (i2c_transfer( 0, chip<<1, &xaddr[4-alen], alen, buffer, len ) != 0); + return (i2c_transfer( 0, chip<<1, &xaddr[4-alen], alen, buffer, len ) != 0); } /*----------------------------------------------------------------------- |