Improve i2c driver slave delay, thanks to Fabrizio Sciarra that provide it * support for master/slave delay (provided patch) * remove some printk that spam logs * introduce new symbols ETRAX_I2C_DYN_ALLOC and ETRAX_I2C_SLAVE_DELAY * cleanup a bit the driver * dump release number
SVN-Revision: 17954
This commit is contained in:
parent
3c5feca158
commit
4b724681e0
2 changed files with 317 additions and 211 deletions
|
@ -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**/
|
||||
|
||||
int i2c_major = I2C_MAJOR;
|
||||
#endif
|
||||
/**END GVC**/
|
||||
|
||||
printk( KERN_INFO "I2C driver v2.2, (c) 1999-2004 Axis Communications AB\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" );
|
||||
|
||||
/**GVC**/
|
||||
printk( KERN_INFO " ==> Improvements done by Geert Vancompernolle - December 2006\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 */
|
||||
|
@ -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 */
|
||||
|
@ -848,7 +852,6 @@ int i2c_stop( void )
|
|||
|
||||
if ( !i2c_sda_is_high() || !i2c_scl_is_high() )
|
||||
{
|
||||
printk( KERN_DEBUG "I2C: EI2CSTOPCOND\n" );
|
||||
return ( EI2CSTOPCOND );
|
||||
}
|
||||
|
||||
|
@ -907,7 +910,6 @@ int i2c_outbyte( unsigned char x )
|
|||
|
||||
if ( !i2c_getack() )
|
||||
{
|
||||
printk( KERN_DEBUG "I2C: EI2CNOACKNLD\n" );
|
||||
return( EI2CNOACKNLD );
|
||||
}
|
||||
|
||||
|
@ -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 );
|
||||
i2c_set_scl( SCL_HIGH );
|
||||
|
||||
#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 );
|
||||
i2c_set_scl( SCL_HIGH );
|
||||
|
||||
#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 );
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
--- a/arch/cris/arch-v10/drivers/Kconfig
|
||||
+++ b/arch/cris/arch-v10/drivers/Kconfig
|
||||
@@ -450,11 +450,18 @@ config ETRAX_I2C
|
||||
Index: linux-2.6.30.8/arch/cris/arch-v10/drivers/Kconfig
|
||||
===================================================================
|
||||
--- linux-2.6.30.8.orig/arch/cris/arch-v10/drivers/Kconfig 2009-10-02 11:31:49.000000000 +0200
|
||||
+++ linux-2.6.30.8/arch/cris/arch-v10/drivers/Kconfig 2009-10-06 10:36:23.000000000 +0200
|
||||
@@ -450,11 +450,31 @@
|
||||
i2c_arg = I2C_READARG(STA013_READ_ADDR, reg);
|
||||
val = ioctl(fd, _IO(ETRAXI2C_IOCTYPE, I2C_READREG), i2c_arg);
|
||||
|
||||
|
@ -10,6 +12,19 @@
|
|||
+ select ETRAX_I2C_USES_PB_NOT_PB_I2C
|
||||
+ help
|
||||
+ Enables an I2C driver with Geert Vancompernolle improvement.
|
||||
+
|
||||
+config ETRAX_I2C_SLAVE_DELAY
|
||||
+ bool "I2C Slave delay support"
|
||||
+ depends on ETRAX_I2C_GVC && EXPERIMENTAL
|
||||
+ help
|
||||
+ Enable this to enhanced master/slave dialog
|
||||
+ Improvement by Positive Going (www.positivegoing.it) and BK srl (www.b-k.it)
|
||||
+
|
||||
+config ETRAX_I2C_DYN_ALLOC
|
||||
+ bool "I2C major device dynamic alloc"
|
||||
+ depends on ETRAX_I2C_GVC && EXPERIMENTAL
|
||||
+ help
|
||||
+ Enable this to dynamicaly alloc major i2c device number
|
||||
+
|
||||
# this is true for most products since PB-I2C seems to be somewhat
|
||||
# flawed..
|
||||
|
@ -20,7 +35,7 @@
|
|||
help
|
||||
Select whether to use the special I2C mode in the PB I/O register or
|
||||
not. This option needs to be selected in order to use some drivers
|
||||
@@ -478,7 +485,7 @@ config ETRAX_I2C_CLK_PORT
|
||||
@@ -478,7 +498,7 @@
|
||||
|
||||
config ETRAX_I2C_EEPROM
|
||||
bool "I2C EEPROM (non-volatile RAM) support"
|
||||
|
@ -29,8 +44,10 @@
|
|||
help
|
||||
Enables I2C EEPROM (non-volatile RAM) on PB0 and PB1 using the I2C
|
||||
driver. Select size option: Probed, 2k, 8k, 16k.
|
||||
--- a/arch/cris/arch-v10/drivers/Makefile
|
||||
+++ b/arch/cris/arch-v10/drivers/Makefile
|
||||
Index: linux-2.6.30.8/arch/cris/arch-v10/drivers/Makefile
|
||||
===================================================================
|
||||
--- linux-2.6.30.8.orig/arch/cris/arch-v10/drivers/Makefile 2009-10-02 11:31:14.000000000 +0200
|
||||
+++ linux-2.6.30.8/arch/cris/arch-v10/drivers/Makefile 2009-10-02 11:31:50.000000000 +0200
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
obj-$(CONFIG_ETRAX_AXISFLASHMAP) += axisflashmap.o
|
||||
|
|
Loading…
Reference in a new issue