@ -91,359 +91,357 @@ static void SetI2CSCL(int x)
}
static int WaitForXfer ( void )
static int WaitForXfer ( void )
{
S3C24X0_I2C * const i2c = S3C24X0_GetBase_I2C ( ) ;
int i , status ;
S3C24X0_I2C * const i2c = S3C24X0_GetBase_I2C ( ) ;
int i , status ;
i = I2C_TIMEOUT * 1000 ;
status = i2c - > IICCON ;
while ( ( i > 0 ) & & ! ( status & I2CCON_IRPND ) ) {
udelay ( 1000 ) ;
i = I2C_TIMEOUT * 10000 ;
status = i2c - > IICCON ;
i - - ;
}
while ( ( i > 0 ) & & ! ( status & I2CCON_IRPND ) ) {
udelay ( 100 ) ;
status = i2c - > IICCON ;
i - - ;
}
return ( status & I2CCON_IRPND ) ? I2C_OK : I2C_NOK_TOUT ;
return ( status & I2CCON_IRPND ) ? I2C_OK : I2C_NOK_TOUT ;
}
static int IsACK ( void )
static int IsACK ( void )
{
S3C24X0_I2C * const i2c = S3C24X0_GetBase_I2C ( ) ;
S3C24X0_I2C * const i2c = S3C24X0_GetBase_I2C ( ) ;
return ( ! ( i2c - > IICSTAT & I2CSTAT_NACK ) ) ;
return ( ! ( i2c - > IICSTAT & I2CSTAT_NACK ) ) ;
}
static void ReadWriteByte ( void )
static void ReadWriteByte ( void )
{
S3C24X0_I2C * const i2c = S3C24X0_GetBase_I2C ( ) ;
S3C24X0_I2C * const i2c = S3C24X0_GetBase_I2C ( ) ;
i2c - > IICCON & = ~ I2CCON_IRPND ;
i2c - > IICCON & = ~ I2CCON_IRPND ;
}
void i2c_init ( int speed , int slaveadd )
{
S3C24X0_I2C * const i2c = S3C24X0_GetBase_I2C ( ) ;
S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO ( ) ;
ulong freq , pres = 16 , div ;
int i , status ;
S3C24X0_I2C * const i2c = S3C24X0_GetBase_I2C ( ) ;
S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO ( ) ;
ulong freq , pres = 16 , div ;
int i , status ;
/* wait for some time to give previous transfer a chance to finish */
/* wait for some time to give previous transfer a chance to finish */
i = I2C_TIMEOUT * 1000 ;
status = i2c - > IICSTAT ;
while ( ( i > 0 ) & & ( status & I2CSTAT_BSY ) ) {
udelay ( 1000 ) ;
i = I2C_TIMEOUT * 1000 ;
status = i2c - > IICSTAT ;
i - - ;
}
while ( ( i > 0 ) & & ( status & I2CSTAT_BSY ) ) {
udelay ( 1000 ) ;
status = i2c - > IICSTAT ;
i - - ;
}
if ( ( status & I2CSTAT_BSY ) | | GetI2CSDA ( ) = = 0 ) {
if ( ( status & I2CSTAT_BSY ) | | GetI2CSDA ( ) = = 0 ) {
# ifdef CONFIG_S3C2410
ulong old_gpecon = gpio - > GPECON ;
ulong old_gpecon = gpio - > GPECON ;
# endif
# ifdef CONFIG_S3C2400
ulong old_gpecon = gpio - > PGCON ;
ulong old_gpecon = gpio - > PGCON ;
# endif
/* bus still busy probably by (most) previously interrupted transfer */
/* bus still busy probably by (most) previously interrupted transfer */
# ifdef CONFIG_S3C2410
/* set I2CSDA and I2CSCL (GPE15, GPE14) to GPIO */
gpio - > GPECON = ( gpio - > GPECON & ~ 0xF0000000 ) | 0x10000000 ;
/* set I2CSDA and I2CSCL (GPE15, GPE14) to GPIO */
gpio - > GPECON = ( gpio - > GPECON & ~ 0xF0000000 ) | 0x10000000 ;
# endif
# ifdef CONFIG_S3C2400
/* set I2CSDA and I2CSCL (PG5, PG6) to GPIO */
gpio - > PGCON = ( gpio - > PGCON & ~ 0x00003c00 ) | 0x00000c00 ;
/* set I2CSDA and I2CSCL (PG5, PG6) to GPIO */
gpio - > PGCON = ( gpio - > PGCON & ~ 0x00003c00 ) | 0x00000c00 ;
# endif
/* toggle I2CSCL until bus idle */
SetI2CSCL ( 0 ) ; udelay ( 1000 ) ;
i = 10 ;
while ( ( i > 0 ) & & ( GetI2CSDA ( ) ! = 1 ) ) {
SetI2CSCL ( 1 ) ; udelay ( 1000 ) ;
SetI2CSCL ( 0 ) ; udelay ( 1000 ) ;
i - - ;
}
SetI2CSCL ( 1 ) ; udelay ( 1000 ) ;
/* toggle I2CSCL until bus idle */
SetI2CSCL ( 0 ) ;
udelay ( 1000 ) ;
i = 10 ;
while ( ( i > 0 ) & & ( GetI2CSDA ( ) ! = 1 ) ) {
SetI2CSCL ( 1 ) ;
udelay ( 1000 ) ;
SetI2CSCL ( 0 ) ;
udelay ( 1000 ) ;
i - - ;
}
SetI2CSCL ( 1 ) ;
udelay ( 1000 ) ;
/* restore pin functions */
/* restore pin functions */
# ifdef CONFIG_S3C2410
gpio - > GPECON = old_gpecon ;
gpio - > GPECON = old_gpecon ;
# endif
# ifdef CONFIG_S3C2400
gpio - > PGCON = old_gpecon ;
gpio - > PGCON = old_gpecon ;
# endif
}
}
/* calculate prescaler and divisor values */
freq = get_PCLK ( ) ;
if ( ( freq / pres / ( 16 + 1 ) ) > speed )
/* set prescaler to 512 */
pres = 512 ;
/* calculate prescaler and divisor values */
freq = get_PCLK ( ) ;
if ( ( freq / pres / ( 16 + 1 ) ) > speed )
/* set prescaler to 512 */
pres = 512 ;
div = 0 ;
while ( ( freq / pres / ( div + 1 ) ) > speed )
div + + ;
div = 0 ;
while ( ( freq / pres / ( div + 1 ) ) > speed )
div + + ;
/* set prescaler, divisor according to freq, also set
ACKGEN , IRQ */
i2c - > IICCON = ( div & 0x0F ) | 0xA0 | ( ( pres = = 512 ) ? 0x40 : 0 ) ;
/* set prescaler, divisor according to freq, also set
* ACKGEN , IRQ */
i2c - > IICCON = ( div & 0x0F ) | 0xA0 | ( ( pres = = 512 ) ? 0x40 : 0 ) ;
/* init to SLAVE REVEIVE and set slaveaddr */
i2c - > IICSTAT = 0 ;
i2c - > IICADD = slaveadd ;
/* program Master Transmit (and implicit STOP) */
i2c - > IICSTAT = I2C_MODE_MT | I2C_TXRX_ENA ;
/* init to SLAVE REVEIVE and set slaveaddr */
i2c - > IICSTAT = 0 ;
i2c - > IICADD = slaveadd ;
/* program Master Transmit (and implicit STOP) */
i2c - > IICSTAT = I2C_MODE_MT | I2C_TXRX_ENA ;
}
/*
cmd_type is 0 for write 1 for read .
addr_len can take any value from 0 - 255 , it is only limited
by the char , we could make it larger if needed . If it is
0 we skip the address write cycle .
*/
* cmd_type is 0 for write , 1 for read .
*
* addr_len can take any value from 0 - 255 , it is only limited
* by the char , we could make it larger if needed . If it is
* 0 we skip the address write cycle .
*/
static
int i2c_transfer ( unsigned char cmd_type ,
unsigned char chip ,
unsigned char addr [ ] ,
unsigned char addr_len ,
unsigned char data [ ] ,
unsigned short data_len )
int i2c_transfer ( unsigned char cmd_type ,
unsigned char chip ,
unsigned char addr [ ] ,
unsigned char addr_len ,
unsigned char data [ ] , unsigned short data_len )
{
S3C24X0_I2C * const i2c = S3C24X0_GetBase_I2C ( ) ;
int i , status , result ;
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 I2C_NOK ;
}
/*CheckDelay(); */
/* Check I2C bus idle */
i = I2C_TIMEOUT * 1000 ;
status = i2c - > IICSTAT ;
while ( ( i > 0 ) & & ( status & I2CSTAT_BSY ) ) {
udelay ( 1000 ) ;
status = i2c - > IICSTAT ;
i - - ;
}
S3C24X0_I2C * const i2c = S3C24X0_GetBase_I2C ( ) ;
int i , status , result ;
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 I2C_NOK ;
}
if ( status & I2CSTAT_BSY ) {
result = I2C_NOK_TOUT ;
return ( result ) ;
}
/* Check I2C bus idle */
i = I2C_TIMEOUT * 1000 ;
status = i2c - > IICSTAT ;
while ( ( i > 0 ) & & ( status & I2CSTAT_BSY ) ) {
udelay ( 1000 ) ;
status = i2c - > IICSTAT ;
i - - ;
}
i2c - > IICCON | = 0x80 ;
if ( status & I2CSTAT_BSY )
return I2C_NOK_TOUT ;
result = I2C_OK ;
i2c - > IICCON | = 0x80 ;
result = I2C_OK ;
switch ( cmd_type ) {
switch ( cmd_type ) {
case I2C_WRITE :
if ( addr & & addr_len ) {
i2c - > IICDS = chip ;
/* send START */
i2c - > IICSTAT = I2C_MODE_MT | I2C_TXRX_ENA | I2C_START_STOP ;
i = 0 ;
while ( ( i < addr_len ) & & ( result = = I2C_OK ) ) {
result = WaitForXfer ( ) ;
i2c - > IICDS = addr [ i ] ;
ReadWriteByte ( ) ;
i + + ;
}
i = 0 ;
while ( ( i < data_len ) & & ( result = = I2C_OK ) ) {
result = WaitForXfer ( ) ;
i2c - > IICDS = data [ i ] ;
ReadWriteByte ( ) ;
i + + ;
}
} else {
i2c - > IICDS = chip ;
/* send START */
i2c - > IICSTAT = I2C_MODE_MT | I2C_TXRX_ENA | I2C_START_STOP ;
i = 0 ;
while ( ( i < data_len ) & & ( result = I2C_OK ) ) {
result = WaitForXfer ( ) ;
i2c - > IICDS = data [ i ] ;
ReadWriteByte ( ) ;
i + + ;
if ( addr & & addr_len ) {
i2c - > IICDS = chip ;
/* send START */
i2c - > IICSTAT = I2C_MODE_MT | I2C_TXRX_ENA | I2C_START_STOP ;
i = 0 ;
while ( ( i < addr_len ) & & ( result = = I2C_OK ) ) {
result = WaitForXfer ( ) ;
i2c - > IICDS = addr [ i ] ;
ReadWriteByte ( ) ;
i + + ;
}
i = 0 ;
while ( ( i < data_len ) & & ( result = = I2C_OK ) ) {
result = WaitForXfer ( ) ;
i2c - > IICDS = data [ i ] ;
ReadWriteByte ( ) ;
i + + ;
}
} else {
i2c - > IICDS = chip ;
/* send START */
i2c - > IICSTAT = I2C_MODE_MT | I2C_TXRX_ENA | I2C_START_STOP ;
i = 0 ;
while ( ( i < data_len ) & & ( result = I2C_OK ) ) {
result = WaitForXfer ( ) ;
i2c - > IICDS = data [ i ] ;
ReadWriteByte ( ) ;
i + + ;
}
}
}
if ( result = = I2C_OK )
result = WaitForXfer ( ) ;
if ( result = = I2C_OK )
result = WaitForXfer ( ) ;
/* send STOP */
i2c - > IICSTAT = I2C_MODE_MR | I2C_TXRX_ENA ;
ReadWriteByte ( ) ;
break ;
/* send STOP */
i2c - > IICSTAT = I2C_MODE_MR | I2C_TXRX_ENA ;
ReadWriteByte ( ) ;
break ;
case I2C_READ :
if ( addr & & addr_len ) {
i2c - > IICSTAT = I2C_MODE_MT | I2C_TXRX_ENA ;
i2c - > IICDS = chip ;
/* send START */
i2c - > IICSTAT | = I2C_START_STOP ;
result = WaitForXfer ( ) ;
if ( IsACK ( ) ) {
i = 0 ;
while ( ( i < addr_len ) & & ( result = = I2C_OK ) ) {
i2c - > IICDS = addr [ i ] ;
ReadWriteByte ( ) ;
result = WaitForXfer ( ) ;
i + + ;
}
i2c - > IICDS = chip ;
/* resend START */
i2c - > IICSTAT = I2C_MODE_MR | I2C_TXRX_ENA | I2C_START_STOP ;
ReadWriteByte ( ) ;
result = WaitForXfer ( ) ;
i = 0 ;
while ( ( i < data_len ) & & ( result = = I2C_OK ) ) {
/* disable ACK for final READ */
if ( i = = data_len - 1 )
i2c - > IICCON & = ~ 0x80 ;
ReadWriteByte ( ) ;
result = WaitForXfer ( ) ;
data [ i ] = i2c - > IICDS ;
i + + ;
}
} else {
result = I2C_NACK ;
}
if ( addr & & addr_len ) {
i2c - > IICSTAT = I2C_MODE_MT | I2C_TXRX_ENA ;
i2c - > IICDS = chip ;
/* send START */
i2c - > IICSTAT | = I2C_START_STOP ;
result = WaitForXfer ( ) ;
if ( IsACK ( ) ) {
i = 0 ;
while ( ( i < addr_len ) & & ( result = = I2C_OK ) ) {
i2c - > IICDS = addr [ i ] ;
ReadWriteByte ( ) ;
result = WaitForXfer ( ) ;
i + + ;
}
i2c - > IICDS = chip ;
/* resend START */
i2c - > IICSTAT = I2C_MODE_MR | I2C_TXRX_ENA |
I2C_START_STOP ;
ReadWriteByte ( ) ;
result = WaitForXfer ( ) ;
i = 0 ;
while ( ( i < data_len ) & & ( result = = I2C_OK ) ) {
/* disable ACK for final READ */
if ( i = = data_len - 1 )
i2c - > IICCON & = ~ 0x80 ;
ReadWriteByte ( ) ;
result = WaitForXfer ( ) ;
data [ i ] = i2c - > IICDS ;
i + + ;
}
} else {
result = I2C_NACK ;
}
} else {
i2c - > IICSTAT = I2C_MODE_MR | I2C_TXRX_ENA ;
i2c - > IICDS = chip ;
/* send START */
i2c - > IICSTAT | = I2C_START_STOP ;
result = WaitForXfer ( ) ;
if ( IsACK ( ) ) {
i = 0 ;
while ( ( i < data_len ) & & ( result = = I2C_OK ) ) {
/* disable ACK for final READ */
if ( i = = data_len - 1 )
i2c - > IICCON & = ~ 0x80 ;
ReadWriteByte ( ) ;
result = WaitForXfer ( ) ;
data [ i ] = i2c - > IICDS ;
i + + ;
}
} else {
result = I2C_NACK ;
i2c - > IICSTAT = I2C_MODE_MR | I2C_TXRX_ENA ;
i2c - > IICDS = chip ;
/* send START */
i2c - > IICSTAT | = I2C_START_STOP ;
result = WaitForXfer ( ) ;
if ( IsACK ( ) ) {
i = 0 ;
while ( ( i < data_len ) & & ( result = = I2C_OK ) ) {
/* disable ACK for final READ */
if ( i = = data_len - 1 )
i2c - > IICCON & = ~ 0x80 ;
ReadWriteByte ( ) ;
result = WaitForXfer ( ) ;
data [ i ] = i2c - > IICDS ;
i + + ;
}
} else {
result = I2C_NACK ;
}
}
}
/* send STOP */
i2c - > IICSTAT = I2C_MODE_MR | I2C_TXRX_ENA ;
ReadWriteByte ( ) ;
break ;
/* send STOP */
i2c - > IICSTAT = I2C_MODE_MR | I2C_TXRX_ENA ;
ReadWriteByte ( ) ;
break ;
default :
printf ( " i2c_transfer: bad call \n " ) ;
result = I2C_NOK ;
break ;
}
printf ( " i2c_transfer: bad call \n " ) ;
result = I2C_NOK ;
break ;
}
return ( result ) ;
return ( result ) ;
}
int i2c_probe ( uchar chip )
{
uchar buf [ 1 ] ;
uchar buf [ 1 ] ;
buf [ 0 ] = 0 ;
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 ( I2C_READ , chip < < 1 , 0 , 0 , buf , 1 ) ! = I2C_OK ) ;
/*
* 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 ( I2C_READ , chip < < 1 , 0 , 0 , buf , 1 ) ! = I2C_OK ) ;
}
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 > 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 ;
}
# ifdef CFG_I2C_EEPROM_ADDR_OVERFLOW
/*
* EEPROM chips that implement " address overflow " are ones
* like Catalyst 24 WC04 / 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 24 WC08 ( 1 Kbyte ) 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 .
*/
if ( alen > 0 )
chip | = ( ( addr > > ( alen * 8 ) ) & CFG_I2C_EEPROM_ADDR_OVERFLOW ) ;
/*
* EEPROM chips that implement " address overflow " are ones
* like Catalyst 24 WC04 / 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 24 WC08 ( 1 Kbyte ) 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 .
*/
if ( alen > 0 )
chip | = ( ( addr > > ( alen * 8 ) ) & CFG_I2C_EEPROM_ADDR_OVERFLOW ) ;
# endif
if ( ( ret = i2c_transfer ( I2C_READ , chip < < 1 , & xaddr [ 4 - alen ] , alen , buffer , len ) ) ! = 0 ) {
printf ( " I2c read: failed %d \n " , ret ) ;
return 1 ;
}
return 0 ;
if ( ( ret =
i2c_transfer ( I2C_READ , 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 > 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 ;
}
# ifdef CFG_I2C_EEPROM_ADDR_OVERFLOW
/*
* EEPROM chips that implement " address overflow " are ones
* like Catalyst 24 WC04 / 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 24 WC08 ( 1 Kbyte ) 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 .
*/
if ( alen > 0 )
chip | = ( ( addr > > ( alen * 8 ) ) & CFG_I2C_EEPROM_ADDR_OVERFLOW ) ;
/*
* EEPROM chips that implement " address overflow " are ones
* like Catalyst 24 WC04 / 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 24 WC08 ( 1 Kbyte ) 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 .
*/
if ( alen > 0 )
chip | = ( ( addr > > ( alen * 8 ) ) & CFG_I2C_EEPROM_ADDR_OVERFLOW ) ;
# endif
return ( i2c_transfer ( I2C_WRITE , chip < < 1 , & xaddr [ 4 - alen ] , alen , buffer , len ) ! = 0 ) ;
return ( i2c_transfer
( I2C_WRITE , chip < < 1 , & xaddr [ 4 - alen ] , alen , buffer ,
len ) ! = 0 ) ;
}
# endif /* CONFIG_HARD_I2C */
# endif /* CONFIG_DRIVER_S3C24X0_I2C */