@ -9,26 +9,21 @@
* !
* ! * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# define DYNAMIC_MAJOR_I2CDEV_NUMBER_ALLOC
//#undef DYNAMIC_MAJOR_I2CDEV_NUMBER_ALLOC
/******************** INCLUDE FILES SECTION ****************************/
# include <linux/module.h>
# include <linux/fs.h>
/**GVC**/
# ifdef DYNAMIC_MAJOR_I2CDEV_NUMBER_ALLOC
# ifdef CONFIG_ETRAX_I2C_DYN_ALLOC
# include <linux/types.h> /* for dev_t */
# include <linux/cdev.h> /* for struct cdev */
# endif
/**END GVC**/
# include <linux/device.h>
# include "etraxi2c.h"
/**GVC**/
# include "i2c_errno.h"
/**END GVC**/
# include <asm/io.h>
# include <asm/delay.h>
@ -37,7 +32,7 @@
# include "i2c_gvc.h"
MODULE_DESCRIPTION ( " I2C Device Driver - 1.1 " ) ;
MODULE_DESCRIPTION ( " I2C Device Driver - 2.3 " ) ;
/*!*********************************************************************
* ! History I2C driver Geert Vancompernolle
@ -57,15 +52,10 @@ MODULE_LICENSE( "GPL" );
# define D( x )
/**GVC**/
# ifndef DYNAMIC_MAJOR_I2CDEV_NUMBER_ALLOC
/**END GVC**/
# ifndef CONFIG_ETRAX_I2C_DYN_ALLOC
# define I2C_MAJOR 123 /* LOCAL/EXPERIMENTAL */
/**GVC**/
# endif
/**END GVC**/
/**GVC**/
# define WAITONEUS 1
/* Following are abbreviations taken from Philips I2C standard */
/* Values are representing time in us and are rounded to next whole number, if relevant */
@ -78,11 +68,14 @@ MODULE_LICENSE( "GPL" );
# define TSUSTO 4 /* Set-up time for STOP condition */
# define TBUF 5 /* Bus-free time between STOP and START condition */
# ifdef CONFIG_ETRAX_I2C_SLAVE_DELAY
# define MAXSCLRETRIES 100
# endif
# define MAXBUSFREERETRIES 5
# define MAXRETRIES 3
# define WRITEADDRESS_MASK ( 0xFE )
# define READADDRESS_MASK ( 0x01 )
/**END GVC**/
# define SCL_HIGH 1
# define SCL_LOW 0
@ -109,6 +102,13 @@ MODULE_LICENSE( "GPL" );
# define i2c_sda_dir_in() \
REG_SHADOW_SET ( R_PORT_PB_DIR , port_pb_dir_shadow , SDABIT , 0 )
# ifdef CONFIG_ETRAX_I2C_SLAVE_DELAY
# define i2c_scl_dir_out() \
REG_SHADOW_SET ( R_PORT_PB_DIR , port_pb_dir_shadow , SCLBIT , 1 )
# define i2c_scl_dir_in() \
REG_SHADOW_SET ( R_PORT_PB_DIR , port_pb_dir_shadow , SCLBIT , 0 )
# endif
/* control the i2c clock and data signals */
# define i2c_set_scl( x ) \
REG_SHADOW_SET ( R_PORT_PB_DATA , port_pb_data_shadow , SCLBIT , x )
@ -118,10 +118,8 @@ MODULE_LICENSE( "GPL" );
/* read status of SDA bit from the i2c interface */
# define i2c_sda_is_high() ( ( ( *R_PORT_PB_READ & ( 1 << SDABIT ) ) ) >> SDABIT )
/**GVC**/
/* read status of SCL bit from the i2c interface */
# define i2c_scl_is_high() ( ( ( *R_PORT_PB_READ & ( 1 << SCLBIT ) ) ) >> SCLBIT )
/**END GVC**/
# else
/* enable or disable the i2c interface */
@ -160,19 +158,13 @@ MODULE_LICENSE( "GPL" );
/****************** STATIC (file scope) VARIABLES **********************/
static DEFINE_SPINLOCK ( i2c_lock ) ; /* Protect directions etc */
/**GVC**/
# ifdef DYNAMIC_MAJOR_I2CDEV_NUMBER_ALLOC
static const char i2c_name [ ] = " i2cgvc " ;
# else
static const char i2c_name [ ] = " i2c " ;
# endif
/**END GVC**/
/****************** PROTOTYPING SECTION *************************/
static int i2c_open ( struct inode * inode , struct file * filp ) ;
static int i2c_release ( struct inode * inode , struct file * filp ) ;
/**GVC**/
static int i2c_command ( unsigned char slave
, unsigned char * wbuf
, unsigned char wlen
@ -181,7 +173,6 @@ static int i2c_command( unsigned char slave
) ;
static int i2c_bus_free_check ( unsigned char maxretries ) ;
static void i2c_finalise ( const char * text , unsigned long irqflags ) ;
/**END GVC**/
/************************************************************************/
@ -267,7 +258,6 @@ static int i2c_ioctl( struct inode *inode
RetVal = i2c_readreg ( I2C_ARGSLAVE ( arg ) , I2C_ARGREG ( arg ) ) ;
break ;
/**GVC**/
/* New functions added by GVC */
case I2C_READ :
copy_from_user ( ( char * ) & i2cdata , ( char * ) arg , sizeof ( I2C_DATA ) ) ;
@ -327,7 +317,6 @@ static int i2c_ioctl( struct inode *inode
}
copy_to_user ( ( char * ) arg , ( char * ) & i2cdata , sizeof ( I2C_DATA ) ) ;
break ;
/**END GVC**/
default :
RetVal = - EINVAL ;
@ -458,7 +447,7 @@ static int i2c_command( unsigned char slave
while ( wlen - - )
{
/* send register data */
if ( EI2CNOERRORS ! = i2c_outbyte ( * wbuf ) )
if ( EI2CNOERRORS ! = i2c_outbyte ( * wbuf ) & & wlen )
{
return ( i2c_finalise ( " I2C: EI2CSENDDATA \n " , irqflags )
, EI2CSENDDATA
@ -525,7 +514,7 @@ static int i2c_command( unsigned char slave
/* Generate final stop condition */
if ( EI2CNOERRORS ! = i2c_stop ( ) )
{
return ( i2c_finalise ( " I2C : EI2CSTOPCOND\n " , irqflags )
return ( i2c_finalise ( " I2C CMD : EI2CSTOPCOND\n " , irqflags )
, EI2CSTOPCOND
) ;
}
@ -700,15 +689,16 @@ int __init i2c_init( void )
* #
* # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
static struct class * i2c_class ;
static int __init i2c_register ( void )
{
int res ;
/**GVC**/
# ifdef DYNAMIC_MAJOR_I2CDEV_NUMBER_ALLOC
# ifdef CONFIG_ETRAX_I2C_DYN_ALLOC
dev_t devt ;
struct cdev * my_i2cdev = NULL ;
# endif
/**END GVC**/
res = i2c_init ( ) ;
@ -717,8 +707,7 @@ static int __init i2c_register( void )
return res ;
}
/**GVC**/
# ifdef DYNAMIC_MAJOR_I2CDEV_NUMBER_ALLOC
# ifdef CONFIG_ETRAX_I2C_DYN_ALLOC
res = alloc_chrdev_region ( & devt , 0 , 1 , i2c_name ) ;
if ( res < 0 )
@ -739,8 +728,9 @@ static int __init i2c_register( void )
printk ( KERN_DEBUG " I2C: EI2CDADDFAIL \n " ) ;
return ( res ) ;
}
int i2c_major = MAJOR ( devt ) ;
# else
/**END GVC**/
res = register_chrdev ( I2C_MAJOR , i2c_name , & i2c_fops ) ;
if ( res < 0 )
@ -748,23 +738,20 @@ static int __init i2c_register( void )
printk ( KERN_ERR " i2c: couldn't get a major number. \n " ) ;
return res ;
}
/**GVC**/
# endif
/**END GVC**/
printk ( KERN_INFO " I2C driver v2.2, (c) 1999-2004 Axis Communications AB \n " ) ;
int i2c_major = I2C_MAJOR ;
# endif
/**GVC**/
printk ( KERN_INFO " ==> Improvements done by Geert Vancompernolle - December 2006 \n " ) ;
printk ( KERN_INFO " I2C: driver v2.3, (c) 1999-2004 Axis Communications AB \n " ) ;
printk ( KERN_INFO " I2C: Improvements by Geert Vancompernolle, Positive Going, BK srl \n " ) ;
# ifdef DYNAMIC_MAJOR_I2CDEV_NUMBER_ALLOC
printk ( KERN_INFO " I2C Major: %d / I2C Name: %s \n " , MAJOR ( devt ) , i2c_name ) ;
# else
/**END GVC**/
printk ( KERN_INFO " I2C Major: %d / I2C Name: %s \n " , I2C_MAJOR , i2c_name ) ;
/**GVC**/
# ifdef CONFIG_ETRAX_I2C_SLAVE_DELAY
printk ( KERN_INFO " I2C: with master/slave delay patch \n " ) ;
# endif
/**END GVC**/
i2c_class = class_create ( THIS_MODULE , " i2c_etrax " ) ;
device_create ( i2c_class , NULL ,
MKDEV ( i2c_major , 0 ) , NULL , i2c_name ) ;
return ( 0 ) ;
} /* i2c_register */
@ -784,32 +771,32 @@ static int __init i2c_register( void )
*/
int i2c_start ( void )
{
/* Set SCL=1, SDA=1 */
i2c_sda_dir_out ( ) ;
i2c_set_sda ( SDA_HIGH ) ;
i2c_delay ( WAITONEUS ) ;
i2c_set_scl ( SCL_HIGH ) ;
i2c_delay ( WAITONEUS ) ;
/* Set SCL=1, SDA=0 */
i2c_set_sda ( SDA_LOW ) ;
i2c_delay ( THDSTA ) ;
/* Set SCL=0, SDA=0 */
i2c_set_scl ( SCL_LOW ) ;
/* We can take 1 us less than defined in spec (5 us), since the next action
* will be to set the dataline high or low and this action is 1 us
* before the clock is put high , so that makes our 5 us .
*/
i2c_delay ( TLOW - WAITONEUS ) ;
if ( i2c_sda_is_high ( ) | | i2c_scl_is_high ( ) )
/* Set SCL=1, SDA=1 */
i2c_sda_dir_out ( ) ;
i2c_set_sda ( SDA_HIGH ) ;
i2c_delay ( WAITONEUS ) ;
i2c_set_scl ( SCL_HIGH ) ;
i2c_delay ( WAITONEUS ) ;
/* Set SCL=1, SDA=0 */
i2c_set_sda ( SDA_LOW ) ;
i2c_delay ( THDSTA ) ;
/* Set SCL=0, SDA=0 */
i2c_set_scl ( SCL_LOW ) ;
/* We can take 1 us less than defined in spec (5 us), since the next action
* will be to set the dataline high or low and this action is 1 us
* before the clock is put high , so that makes our 5 us .
*/
i2c_delay ( TLOW - WAITONEUS ) ;
if ( i2c_sda_is_high ( ) | | i2c_scl_is_high ( ) )
{
printk ( KERN_DEBUG " I2C: EI2CSTRTCOND \n " ) ;
return ( EI2CSTRTCOND ) ;
printk ( KERN_DEBUG " I2C: EI2CSTRTCOND \n " ) ;
return ( EI2CSTRTCOND ) ;
}
return ( EI2CNOERRORS ) ;
return ( EI2CNOERRORS ) ;
} /* i2c_start */
@ -827,6 +814,9 @@ int i2c_start( void )
*/
int i2c_stop ( void )
{
# ifdef CONFIG_ETRAX_I2C_SLAVE_DELAY
int n = MAXSCLRETRIES ;
# endif
i2c_sda_dir_out ( ) ;
/* Set SCL=0, SDA=0 */
@ -837,7 +827,21 @@ int i2c_stop( void )
i2c_delay ( WAITONEUS ) ;
/* Set SCL=1, SDA=0 */
# ifdef CONFIG_ETRAX_I2C_SLAVE_DELAY
i2c_set_scl ( SCL_HIGH ) ;
i2c_scl_dir_in ( ) ;
for ( ; n > 0 ; n - - )
{
if ( i2c_scl_is_high ( ) )
break ;
i2c_delay ( TSUSTO ) ;
}
i2c_scl_dir_out ( ) ;
# else
i2c_set_scl ( SCL_HIGH ) ;
# endif
i2c_delay ( TSUSTO ) ;
/* Set SCL=1, SDA=1 */
@ -847,10 +851,9 @@ int i2c_stop( void )
i2c_sda_dir_in ( ) ;
if ( ! i2c_sda_is_high ( ) | | ! i2c_scl_is_high ( ) )
{
printk ( KERN_DEBUG " I2C: EI2CSTOPCOND \n " ) ;
return ( EI2CSTOPCOND ) ;
}
{
return ( EI2CSTOPCOND ) ;
}
return ( EI2CNOERRORS ) ;
} /* i2c_stop */
@ -906,10 +909,9 @@ int i2c_outbyte( unsigned char x )
i2c_sda_dir_in ( ) ;
if ( ! i2c_getack ( ) )
{
printk ( KERN_DEBUG " I2C: EI2CNOACKNLD \n " ) ;
{
return ( EI2CNOACKNLD ) ;
}
}
return ( EI2CNOERRORS ) ;
} /* i2c_outbyte */
@ -929,6 +931,9 @@ int i2c_outbyte( unsigned char x )
*/
unsigned char i2c_inbyte ( void )
{
# ifdef CONFIG_ETRAX_I2C_SLAVE_DELAY
int n = MAXSCLRETRIES ;
# endif
unsigned char aBitByte = 0 ;
unsigned char Mask = 0x80 ; /* !!! ATTENTION: do NOT use 'char', otherwise shifting is wrong!!! */
/* Must be UNSIGNED, not SIGNED! */
@ -940,7 +945,20 @@ unsigned char i2c_inbyte( void )
while ( Mask ! = 0 )
{
# ifdef CONFIG_ETRAX_I2C_SLAVE_DELAY
i2c_scl_dir_in ( ) ;
for ( ; n > 0 ; n - - )
{
if ( i2c_scl_is_high ( ) )
break ;
i2c_delay ( THIGH ) ;
}
i2c_set_scl ( SCL_HIGH ) ;
i2c_scl_dir_out ( ) ;
# else
i2c_set_scl ( SCL_HIGH ) ;
# endif
i2c_delay ( THIGH ) ;
if ( i2c_sda_is_high ( ) )
@ -978,6 +996,9 @@ unsigned char i2c_inbyte( void )
int i2c_getack ( void )
{
int ack = 1 ;
# ifdef CONFIG_ETRAX_I2C_SLAVE_DELAY
int n = MAXSCLRETRIES ;
# endif
/* generate ACK clock pulse */
i2c_set_scl ( SCL_HIGH ) ;
@ -985,8 +1006,34 @@ int i2c_getack( void )
/* switch off I2C */
i2c_disable ( ) ;
# ifdef CONFIG_ETRAX_I2C_SLAVE_DELAY
/* set clock low */
i2c_set_scl ( SCL_LOW ) ;
/* now wait for ack */
i2c_delay ( THIGH ) ;
/* set clock as input */
i2c_scl_dir_in ( ) ;
/* wait for clock to rise (n=MAXSCLRETRIES) */
for ( ; n > 0 ; n - - )
{
if ( i2c_scl_is_high ( ) )
break ;
i2c_delay ( THIGH ) ;
}
i2c_set_scl ( SCL_HIGH ) ;
i2c_scl_dir_out ( ) ;
i2c_delay ( THIGH ) ;
# else
/* now wait for ack */
i2c_delay ( THIGH ) ;
# endif
/* check for ack: if SDA is high, then NACK, else ACK */
if ( i2c_sda_is_high ( ) )
{
@ -1024,6 +1071,10 @@ int i2c_getack( void )
*/
void i2c_sendack ( void )
{
# ifdef CONFIG_ETRAX_I2C_SLAVE_DELAY
int n = MAXSCLRETRIES ;
# endif
/* enable output */
/* Clock has been set to TLOW already at end of i2c_inbyte()
* and i2c_outbyte ( ) , so no need to do it again .
@ -1033,8 +1084,25 @@ void i2c_sendack( void )
i2c_set_sda ( SDA_LOW ) ;
/* generate clock pulse */
i2c_delay ( TSUDAT ) ;
# ifdef CONFIG_ETRAX_I2C_SLAVE_DELAY
i2c_scl_dir_in ( ) ;
/* wait for clock to rise (n=MAXSCLRETRIES) */
for ( ; n > 0 ; n - - )
{
if ( i2c_scl_is_high ( ) )
break ;
i2c_delay ( THIGH ) ;
}
i2c_set_scl ( SCL_HIGH ) ;
i2c_scl_dir_out ( ) ;
i2c_delay ( THIGH ) ;
# else
i2c_set_scl ( SCL_HIGH ) ;
i2c_delay ( THIGH ) ;
# endif
i2c_set_scl ( SCL_LOW ) ;
i2c_delay ( THDDAT ) ;
/* reset data out */
@ -1061,6 +1129,10 @@ void i2c_sendack( void )
*/
void i2c_sendnack ( void )
{
# ifdef CONFIG_ETRAX_I2C_SLAVE_DELAY
int n = MAXSCLRETRIES ;
# endif
/* make sure the SDA line is set high prior to activation of the output.
* this way , you avoid an unnecessary peak to ground when a NACK has to
* be created .
@ -1072,8 +1144,25 @@ void i2c_sendnack( void )
/* generate clock pulse */
i2c_delay ( TSUDAT ) ;
# ifdef CONFIG_ETRAX_I2C_SLAVE_DELAY
i2c_scl_dir_in ( ) ;
/* wait for clock to rise (n=MAXSCLRETRIES) */
for ( ; n > 0 ; n - - )
{
if ( i2c_scl_is_high ( ) )
break ;
i2c_delay ( THIGH ) ;
}
i2c_set_scl ( SCL_HIGH ) ;
i2c_scl_dir_out ( ) ;
i2c_delay ( THIGH ) ;
# else
i2c_set_scl ( SCL_HIGH ) ;
i2c_delay ( THIGH ) ;
# endif
i2c_set_scl ( SCL_LOW ) ;
i2c_delay ( TSUDAT ) ;
i2c_set_sda ( SDA_LOW ) ;