summaryrefslogtreecommitdiff
path: root/target/linux/etrax/files-2.6.30/arch
diff options
context:
space:
mode:
authorclaudio <claudio@3c298f89-4303-0410-b956-a3cf2f4a3e73>2009-10-06 09:20:30 +0000
committerclaudio <claudio@3c298f89-4303-0410-b956-a3cf2f4a3e73>2009-10-06 09:20:30 +0000
commit8bbe73f1de074e761fb7ed7ce4cde7de1f70991d (patch)
tree598ee2805a7f6067a886847535d0719197fdf63a /target/linux/etrax/files-2.6.30/arch
parent25d531ca58cf7921cdab22b63251b9c9fb3f20bb (diff)
[etrax] 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 git-svn-id: svn://svn.openwrt.org/openwrt/trunk@17954 3c298f89-4303-0410-b956-a3cf2f4a3e73
Diffstat (limited to 'target/linux/etrax/files-2.6.30/arch')
-rw-r--r--target/linux/etrax/files-2.6.30/arch/cris/arch-v10/drivers/i2c_gvc.c2719
1 files changed, 1404 insertions, 1315 deletions
diff --git a/target/linux/etrax/files-2.6.30/arch/cris/arch-v10/drivers/i2c_gvc.c b/target/linux/etrax/files-2.6.30/arch/cris/arch-v10/drivers/i2c_gvc.c
index 681712f5f3..e47bc64592 100644
--- a/target/linux/etrax/files-2.6.30/arch/cris/arch-v10/drivers/i2c_gvc.c
+++ b/target/linux/etrax/files-2.6.30/arch/cris/arch-v10/drivers/i2c_gvc.c
@@ -1,1315 +1,1404 @@
-/*!***************************************************************************
-*!
-*! FILE NAME : i2c.c
-*!
-*!
-*! ---------------------------------------------------------------------------
-*!
-*! ( C ) Copyright 1999-2002 Axis Communications AB, LUND, SWEDEN
-*!
-*!***************************************************************************/
-
-#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
-#include <linux/types.h> /* for dev_t */
-#include <linux/cdev.h> /* for struct cdev */
-#endif
-/**END GVC**/
-
-#include "etraxi2c.h"
-
-/**GVC**/
-#include "i2c_errno.h"
-/**END GVC**/
-
-#include <asm/io.h>
-#include <asm/delay.h>
-#include <asm/arch/io_interface_mux.h>
-#include <asm/uaccess.h>
-
-#include "i2c_gvc.h"
-
-MODULE_DESCRIPTION( "I2C Device Driver - 1.1" );
-
-/*!*********************************************************************
- *!History I2C driver Geert Vancompernolle
- *!---------------------------------------
- *!
- *! - v1.0:
- *! First official version.
- *!
- *! - v1.1:
- *! Changes to remove unwanted spikes at ACK/NACK time.
- *!
- *!*********************************************************************/
-
-MODULE_LICENSE( "GPL" );
-
-/****************** MACRO's **********************/
-
-#define D( x )
-
-/**GVC**/
-#ifndef DYNAMIC_MAJOR_I2CDEV_NUMBER_ALLOC
-/**END GVC**/
-#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 */
-#define THDSTA 4 /* Hold delay time for (repeated) START condition */
-#define TLOW 5 /* LOW period of the SCL clock */
-#define THDDAT 1 /* Hold delay time for DATA: value of 0 is allowed but 1 taken to be sure */
-#define TSUDAT 1 /* Set-up time for DATA */
-#define THIGH 4 /* HIGH period of the SCL clock */
-#define TSUSTA 5 /* Set-up time for a repeated START condition */
-#define TSUSTO 4 /* Set-up time for STOP condition */
-#define TBUF 5 /* Bus-free time between STOP and START condition */
-
-#define MAXBUSFREERETRIES 5
-#define MAXRETRIES 3
-#define WRITEADDRESS_MASK ( 0xFE )
-#define READADDRESS_MASK ( 0x01 )
-/**END GVC**/
-
-#define SCL_HIGH 1
-#define SCL_LOW 0
-#define SDA_HIGH 1
-#define SDA_LOW 0
-
-#ifdef CONFIG_ETRAX_I2C_USES_PB_NOT_PB_I2C
-/* Use PB and not PB_I2C */
-#ifndef CONFIG_ETRAX_I2C_DATA_PORT
-#define CONFIG_ETRAX_I2C_DATA_PORT 0
-#endif
-#ifndef CONFIG_ETRAX_I2C_CLK_PORT
-#define CONFIG_ETRAX_I2C_CLK_PORT 1
-#endif
-
-#define SDABIT CONFIG_ETRAX_I2C_DATA_PORT
-#define SCLBIT CONFIG_ETRAX_I2C_CLK_PORT
-#define i2c_enable()
-#define i2c_disable()
-
-/* enable or disable output-enable, to select output or input on the i2c bus */
-#define i2c_sda_dir_out() \
- REG_SHADOW_SET( R_PORT_PB_DIR, port_pb_dir_shadow, SDABIT, 1 )
-#define i2c_sda_dir_in() \
- REG_SHADOW_SET( R_PORT_PB_DIR, port_pb_dir_shadow, SDABIT, 0 )
-
-/* 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 )
-#define i2c_set_sda( x ) \
- REG_SHADOW_SET( R_PORT_PB_DATA, port_pb_data_shadow, SDABIT, x )
-
-/* 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 */
-#define i2c_enable() *R_PORT_PB_I2C = ( port_pb_i2c_shadow |= IO_MASK( R_PORT_PB_I2C, i2c_en ) )
-#define i2c_disable() *R_PORT_PB_I2C = ( port_pb_i2c_shadow &= ~IO_MASK( R_PORT_PB_I2C, i2c_en ) )
-
-/* enable or disable output-enable, to select output or input on the i2c bus */
-#define i2c_sda_dir_out() \
- *R_PORT_PB_I2C = ( port_pb_i2c_shadow &= ~IO_MASK( R_PORT_PB_I2C, i2c_oe_ ) ); \
- REG_SHADOW_SET( R_PORT_PB_DIR, port_pb_dir_shadow, 0, 1 );
-#define i2c_sda_dir_in() \
- *R_PORT_PB_I2C = ( port_pb_i2c_shadow |= IO_MASK( R_PORT_PB_I2C, i2c_oe_ ) ); \
- REG_SHADOW_SET( R_PORT_PB_DIR, port_pb_dir_shadow, 0, 0 );
-
-/* control the i2c clock and data signals */
-#define i2c_set_scl( x ) \
- *R_PORT_PB_I2C = ( port_pb_i2c_shadow = ( port_pb_i2c_shadow & \
- ~IO_MASK( R_PORT_PB_I2C, i2c_set_scl ) ) | IO_FIELD( R_PORT_PB_I2C, i2c_set_scl, ( x ) ) ); \
- REG_SHADOW_SET( R_PORT_PB_DATA, port_pb_data_shadow, 1, x );
-
-#define i2c_set_sda( x ) \
- *R_PORT_PB_I2C = ( port_pb_i2c_shadow = ( port_pb_i2c_shadow & \
- ~IO_MASK( R_PORT_PB_I2C, i2c_d ) ) | IO_FIELD( R_PORT_PB_I2C, i2c_d, ( x ) ) ); \
- REG_SHADOW_SET( R_PORT_PB_DATA, port_pb_data_shadow, 0, x );
-
-/* read a bit from the i2c interface */
-#define i2c_sda_is_high() ( *R_PORT_PB_READ & 0x1 )
-#endif
-
-/* use the kernels delay routine */
-#define i2c_delay( usecs ) udelay( usecs )
-
-
-/****************** TYPEDEF's **********************/
-
-
-/****************** 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
- , unsigned char* rbuf
- , unsigned char rlen
- );
-static int i2c_bus_free_check( unsigned char maxretries );
-static void i2c_finalise( const char* text, unsigned long irqflags );
-/**END GVC**/
-
-
-/************************************************************************/
-/****************** AUXILIARIES *************************/
-/************************************************************************/
-
-/*#---------------------------------------------------------------------------
- *#
- *# FUNCTION NAME: i2c_open
- *#
- *# DESCRIPTION : opens an I2C device
- *#
- *# PARAMETERS : *inode: reference to inode
- *# *filp : reference to file pointer
- *#
- *#---------------------------------------------------------------------------
- */
-static int i2c_open( struct inode *inode, struct file *filp )
-{
- return 0;
-} /* i2c_open */
-
-
-/*#---------------------------------------------------------------------------
- *#
- *# FUNCTION NAME: i2c_release
- *#
- *# DESCRIPTION : Releases the I2C device
- *#
- *# PARAMETERS : *inode: reference to inode
- *# *filp : reference to file pointer
- *#
- *#---------------------------------------------------------------------------
- */
-static int i2c_release( struct inode *inode, struct file *filp )
-{
- return 0;
-} /* i2c_release */
-
-
-/*#---------------------------------------------------------------------------
- *#
- *# FUNCTION NAME: i2c_ioctl
- *#
- *# DESCRIPTION : Main device API: ioctl's to write/read
- *# to/from i2c registers
- *#
- *# PARAMETERS : *inode: reference to inode
- *# *filp : reference to file pointer
- *# cmd : command to be executed during the ioctl call
- *# arg : pointer to a structure with the data???
- *#
- *# RETURN : result of the ioctl call
- *#
- *#---------------------------------------------------------------------------
- */
-static int i2c_ioctl( struct inode *inode
- , struct file *file
- , unsigned int cmd
- , unsigned long arg
- )
-{
- /* the acme ioctls */
- I2C_DATA i2cdata;
- int RetVal = EI2CNOERRORS;
-
- if ( _IOC_TYPE( cmd ) != ETRAXI2C_IOCTYPE )
- {
- return ( -EINVAL );
- }
-
- switch ( _IOC_NR( cmd ) )
- {
- case I2C_WRITEREG:
- /* write to an i2c slave */
- RetVal = i2c_writereg( I2C_ARGSLAVE( arg )
- , I2C_ARGREG( arg )
- , I2C_ARGVALUE( arg )
- );
- break;
-
- case I2C_READREG:
- 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 ) );
- {
- int RetryCntr = MAXRETRIES;
-
- do
- {
- RetVal = i2c_command( i2cdata.slave
- , NULL
- , 0
- , i2cdata.rbuf
- , i2cdata.rlen
- );
- } while ( ( EI2CNOERRORS != RetVal )
- &&( --RetryCntr )
- );
- }
- copy_to_user( (char*)arg, (char*)&i2cdata, sizeof( I2C_DATA ) );
- break;
-
- case I2C_WRITE:
- copy_from_user( (char*)&i2cdata, (char*)arg, sizeof( I2C_DATA ) );
- {
- int RetryCntr = MAXRETRIES;
-
- do
- {
- RetVal = i2c_command( i2cdata.slave
- , i2cdata.wbuf
- , i2cdata.wlen
- , NULL
- , 0
- );
- } while ( ( EI2CNOERRORS != RetVal )
- &&( --RetryCntr )
- );
- }
- break;
-
- case I2C_WRITEREAD:
- copy_from_user( (char*)&i2cdata, (char*)arg, sizeof( I2C_DATA ) );
- {
- int RetryCntr = MAXRETRIES;
-
- do
- {
- RetVal = i2c_command( i2cdata.slave
- , i2cdata.wbuf
- , i2cdata.wlen
- , i2cdata.rbuf
- , i2cdata.rlen
- );
- } while ( ( EI2CNOERRORS != RetVal )
- &&( --RetryCntr )
- );
- }
- copy_to_user( (char*)arg, (char*)&i2cdata, sizeof( I2C_DATA ) );
- break;
-/**END GVC**/
-
- default:
- RetVal = -EINVAL;
- }
-
- return ( -RetVal );
-} /* i2c_ioctl */
-
-
-/*#---------------------------------------------------------------------------
- *#
- *# FUNCTION NAME: i2c_command
- *#
- *# DESCRIPTION : general routine to read/write bytes from an I2C device
- *#
- *# 'i2c_command()' sends wlen bytes to the I2c bus and receives
- *# rlen bytes from the I2c bus.
- *# The data to be send must be placed in wbuf[ 0 ] upto wbuf[ wlen - 1 ).
- *# The data to be received is assembled in rbuf[ 0 ] upto rbuf[ rlen - 1 ].
- *#
- *# If no data is to be sent or received, put appropriate buffer parameter
- *# to "NULL" and appropriate length parameter to "0".
- *#
- *# PARAMETERS : slave = slave address of the I2C device
- *# wbuf = address of first element of write buffer (wbuf)
- *# wlen = number of bytes to be written to slave
- *# rbuf = address of first element of read buffer (rbuf)
- *# rlen = number of bytes to be read from slave
- *#
- *# RETURN :
- *# EI2CNOERRORS: I2C communication went fine
- *# EI2CBUSNFREE: I2C bus is not free
- *# EI2CWADDRESS: I2C write address failed
- *# EI2CRADDRESS: I2C read address failed
- *# EI2CSENDDATA: I2C send data failed
- *# EI2CRECVDATA: I2C receive data failed
- *# EI2CSTRTCOND: I2C start condition failed
- *# EI2CRSTACOND: I2C repeated start condition failed
- *# EI2CSTOPCOND: I2C stop condition failed
- *# EI2CNOSNDBYT: I2C no bytes to be sent
- *# EI2CNOSNDBUF: I2C no send buffer defined
- *# EI2CNORCVBYT: I2C no bytes to be received
- *# EI2CNORCVBUF: I2C no receive buffer defined
- *# EI2CNOACKNLD: I2C no acknowledge received
- *#
- *# REMARK :
- *# First, the send part is completed.
- *# In the send routine, there is no stop generated. This is because maybe
- *# a repeated start condition must be generated.
- *# This happens when we want to receive some data from the I2c bus. If not,
- *# at the end of the general I2c loop the stopcondition is generated.
- *# If, on the contrary, there are a number of bytes to be received, a new
- *# startcondition is generated in the 'if' part of the main I2c routine,
- *# which controls the receiving part.
- *# Only when the receiving of data is finished, a final stopcondition is
- *# generated.
- *#
- *#---------------------------------------------------------------------------
- */
-static int i2c_command( unsigned char slave
- , unsigned char* wbuf
- , unsigned char wlen
- , unsigned char* rbuf
- , unsigned char rlen
- )
-{
- /* Check arguments and report error if relevant... */
- if ( ( wlen > 0 ) && ( wbuf == NULL ) )
- {
- printk( KERN_DEBUG "I2C: EI2CNOSNDBUF\n" );
- return ( EI2CNOSNDBUF );
- }
- else if ( ( wlen == 0 ) && ( wbuf != NULL ) )
- {
- printk( KERN_DEBUG "I2C: EI2CNOSNDBYT\n" );
- return ( EI2CNOSNDBYT );
- }
- else if ( ( rlen > 0 ) && ( rbuf == NULL ) )
- {
- printk( KERN_DEBUG "I2C: EI2CNORCVBUF\n" );
- return ( EI2CNORCVBUF );
- }
- else if ( ( rlen == 0 ) && ( rbuf != NULL ) )
- {
- printk( KERN_DEBUG "I2C: EI2CNORCVBYT\n" );
- return ( EI2CNORCVBYT );
- }
- else if ( EI2CBUSNFREE == i2c_bus_free_check( MAXBUSFREERETRIES ) )
- {
- /* There's no need to try more, since we weren't even
- * able to start the I2C communication.
- * So, no IRQ flags are stored yet, no changes to any other
- * stuff like START, STOP, SENDBYTES...
- * Result, simply write down the error and return the correct error code.
- */
- printk( KERN_DEBUG "I2C: EI2CBUSNFREE\n" );
- return ( EI2CBUSNFREE );
- }
- else
- {
- /* Finally... We made it... */
- unsigned long irqflags = 0;
-
- /* we don't like to be interrupted */
- local_irq_save( irqflags );
-
- /* Check if there are bytes to be send,
- * or if you immediately want to receive data.
- */
- if ( 0 < wlen )
- {
- /* start I2C communication */
- if ( EI2CNOERRORS != i2c_start() )
- {
- return ( i2c_finalise( "I2C: EI2CSTRTCOND\n", irqflags )
- , EI2CSTRTCOND
- );
- }
-
- /* send slave address: xxxxxxx0B (last bit must be zero) */
- if ( EI2CNOERRORS != i2c_outbyte( slave & WRITEADDRESS_MASK ) )
- {
- return ( i2c_finalise( "I2C: EI2CWADDRESS\n", irqflags )
- , EI2CWADDRESS
- );
- }
-
- while ( wlen-- )
- {
- /* send register data */
- if ( EI2CNOERRORS != i2c_outbyte( *wbuf ) )
- {
- return ( i2c_finalise( "I2C: EI2CSENDDATA\n", irqflags )
- , EI2CSENDDATA
- );
- }
-
- wbuf++;
- };
-
- i2c_delay( TLOW );
- }
-
- /*
- * Receiving data from I2c_bus
- * If there are bytes to be received, a new start condition is
- * generated => Repeated Startcondition.
- * A final stopcondition is generated at the end of the main I2c
- * routine.
- */
- if ( 0 < rlen )
- {
- /*
- * Generate start condition if wlen == 0
- * or repeated start condition if wlen != 0...
- */
- if ( EI2CNOERRORS != i2c_start() )
- {
- return ( i2c_finalise( ( ( 0 < wlen )
- ? "I2C: EI2CRSTACOND\n"
- : "I2C: EI2CSTRTCOND\n"
- )
- , irqflags
- )
- , ( ( 0 < wlen ) ? EI2CRSTACOND : EI2CSTRTCOND )
- );
- }
-
- /* Send ReadAddress: xxxxxxx1B (last bit must be one) */
- if ( EI2CNOERRORS != i2c_outbyte( slave | READADDRESS_MASK ) )
- {
- return ( i2c_finalise( "I2C: EI2CRADDRESS\n", irqflags )
- , EI2CRADDRESS
- );
- }
-
- while ( rlen-- )
- {
- /* fetch register */
- *rbuf = i2c_inbyte();
- rbuf++;
-
- /* last received byte needs to be NACK-ed instead of ACK-ed */
- if ( rlen )
- {
- i2c_sendack();
- }
- else
- {
- i2c_sendnack();
- }
- };
- }
-
- /* Generate final stop condition */
- if ( EI2CNOERRORS != i2c_stop() )
- {
- return ( i2c_finalise( "I2C: EI2CSTOPCOND\n", irqflags )
- , EI2CSTOPCOND
- );
- }
-
- /* enable interrupt again */
- local_irq_restore( irqflags );
- }
-
- return ( EI2CNOERRORS );
-} /* i2c_command */
-
-
-/*#---------------------------------------------------------------------------
- *#
- *# FUNCTION NAME: i2c_bus_free_check
- *#
- *# DESCRIPTION : checks if the I2C bus is free before starting
- *# an I2C communication
- *#
- *# PARAMETERS : maxretries, the number of times we will try to release
- *# the I2C bus
- *#
- *# RETURN : I2cStatus_I2cBusNotFreeError in case the bus is not free,
- *# I2cStatus_I2cNoError otherwise
- *#
- *#---------------------------------------------------------------------------
- */
-static int i2c_bus_free_check( unsigned char maxretries )
-{
- i2c_sda_dir_in(); /* Release SDA line */
- i2c_set_scl( SCL_HIGH ); /* put SCL line high */
-
- i2c_delay( WAITONEUS );
-
- while ( ( !i2c_sda_is_high() || !i2c_scl_is_high() )
- &&( maxretries-- )
- )
- {
- /* Try to release I2C bus by generating STOP conditions */
- i2c_stop();
- }
-
- if ( 0 == maxretries )
- {
- printk( KERN_DEBUG "I2C: EI2CBUSNFREE\n" );
- return ( EI2CBUSNFREE );
- }
- else
- {
- return ( EI2CNOERRORS );
- }
-} /* i2c_bus_free_check */
-
-
-static void i2c_finalise( const char* errortxt
- , unsigned long irqflags
- )
-{
- printk( KERN_DEBUG "%s", errortxt );
- local_irq_restore( irqflags );
- /* The least we can do when things go terribly wrong,
- * is to try to release the bus.
- * If this fails, well, then I don't know
- * what I can do more for the moment...
- */
- (void)i2c_bus_free_check( MAXBUSFREERETRIES );
-} /* i2c_finalise */
-
-
-static struct file_operations i2c_fops =
-{
- .owner = THIS_MODULE
-, .ioctl = i2c_ioctl
-, .open = i2c_open
-, .release = i2c_release
-};
-
-
-/***********************************************************************/
-/************* EXTERNAL FUNCTION DEFINITION SECTION ********************/
-/***********************************************************************/
-
-/*#---------------------------------------------------------------------------
- *#
- *# FUNCTION NAME: i2c_init
- *#
- *# DESCRIPTION : initialises the I2C device driver
- *#
- *# PARAMETERS :
- *#
- *#---------------------------------------------------------------------------
- */
-int __init i2c_init( void )
-{
- static int res = 0;
- static int first = 1;
-
- if ( !first )
- {
- return res;
- }
-
- first = 0;
-
- /* Setup and enable the Port B I2C interface */
-
-#ifndef CONFIG_ETRAX_I2C_USES_PB_NOT_PB_I2C
- /* here, we're using the dedicated I2C pins of FoxBoard */
- if ( ( res = cris_request_io_interface( if_i2c, "I2C" ) ) )
- {
- printk( KERN_CRIT "i2c_init: Failed to get IO interface\n" );
- return res;
- }
-
- *R_PORT_PB_I2C = port_pb_i2c_shadow |=
- IO_STATE( R_PORT_PB_I2C, i2c_en, on ) |
- IO_FIELD( R_PORT_PB_I2C, i2c_d, 1 ) |
- IO_FIELD( R_PORT_PB_I2C, i2c_set_scl, 1 ) |
- IO_STATE( R_PORT_PB_I2C, i2c_oe_, enable );
-
- port_pb_dir_shadow &= ~IO_MASK( R_PORT_PB_DIR, dir0 );
- port_pb_dir_shadow &= ~IO_MASK( R_PORT_PB_DIR, dir1 );
-
- *R_PORT_PB_DIR = ( port_pb_dir_shadow |=
- IO_STATE( R_PORT_PB_DIR, dir0, input ) |
- IO_STATE( R_PORT_PB_DIR, dir1, output ) );
-#else
- /* If everything goes fine, res = 0, meaning "if" fails =>
- * will do the "else" too and as such initialise the clock port...
- * Clever trick!
- */
- if ( ( res = cris_io_interface_allocate_pins( if_i2c
- , 'b'
- , CONFIG_ETRAX_I2C_DATA_PORT
- , CONFIG_ETRAX_I2C_DATA_PORT
- )
- )
- )
- {
- printk( KERN_WARNING "i2c_init: Failed to get IO pin for I2C data port\n" );
- return ( res );
- }
- /* Same here...*/
- else if ( ( res = cris_io_interface_allocate_pins( if_i2c
- , 'b'
- , CONFIG_ETRAX_I2C_CLK_PORT
- , CONFIG_ETRAX_I2C_CLK_PORT
- )
- )
- )
- {
- cris_io_interface_free_pins( if_i2c
- , 'b'
- , CONFIG_ETRAX_I2C_DATA_PORT
- , CONFIG_ETRAX_I2C_DATA_PORT
- );
- printk( KERN_WARNING "i2c_init: Failed to get IO pin for I2C clk port\n" );
- }
-#endif
-
- return ( res );
-} /* i2c_init */
-
-
-/*#---------------------------------------------------------------------------
- *#
- *# FUNCTION NAME: i2c_register
- *#
- *# DESCRIPTION : this registers the i2c driver as a character device
- *#
- *# PARAMETERS :
- *#
- *#---------------------------------------------------------------------------
- */
-static int __init i2c_register( void )
-{
- int res;
-/**GVC**/
-#ifdef DYNAMIC_MAJOR_I2CDEV_NUMBER_ALLOC
- dev_t devt;
- struct cdev *my_i2cdev = NULL;
-#endif
-/**END GVC**/
-
- res = i2c_init();
-
- if ( res < 0 )
- {
- return res;
- }
-
-/**GVC**/
-#ifdef DYNAMIC_MAJOR_I2CDEV_NUMBER_ALLOC
- res = alloc_chrdev_region( &devt, 0, 1, i2c_name );
-
- if ( res < 0 )
- {
- printk( KERN_DEBUG "I2C: EI2CNOMNUMBR\n" );
- return ( res );
- }
-
- my_i2cdev = cdev_alloc();
- my_i2cdev->ops = &i2c_fops;
- my_i2cdev->owner = THIS_MODULE;
-
- /* make device "alive" */
- res = cdev_add( my_i2cdev, devt, 1 );
-
- if ( res < 0 )
- {
- printk( KERN_DEBUG "I2C: EI2CDADDFAIL\n" );
- return ( res );
- }
-#else
-/**END GVC**/
- res = register_chrdev( I2C_MAJOR, i2c_name, &i2c_fops );
-
- if ( res < 0 )
- {
- 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" );
-
-/**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**/
-#endif
-/**END GVC**/
-
- return ( 0 );
-} /* i2c_register */
-
-
-/*#---------------------------------------------------------------------------
- *#
- *# FUNCTION NAME: i2c_start
- *#
- *# DESCRIPTION : generate i2c start condition
- *#
- *# PARAMETERS : none
- *#
- *# RETURN : EI2CNOERRORS if OK, EI2CSTRTCOND otherwise
- *#
- *#---------------------------------------------------------------------------
- */
-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() )
- {
- printk( KERN_DEBUG "I2C: EI2CSTRTCOND\n" );
- return ( EI2CSTRTCOND );
- }
-
- return ( EI2CNOERRORS );
-} /* i2c_start */
-
-
-/*#---------------------------------------------------------------------------
- *#
- *# FUNCTION NAME: i2c_stop
- *#
- *# DESCRIPTION : generate i2c stop condition
- *#
- *# PARAMETERS : none
- *#
- *# RETURN : none
- *#
- *#---------------------------------------------------------------------------
- */
-int i2c_stop( void )
-{
- i2c_sda_dir_out();
-
- /* Set SCL=0, SDA=0 */
- /* Don't change order, otherwise you might generate a start condition! */
- i2c_set_scl( SCL_LOW );
- i2c_delay( WAITONEUS );
- i2c_set_sda( SDA_LOW );
- i2c_delay( WAITONEUS );
-
- /* Set SCL=1, SDA=0 */
- i2c_set_scl( SCL_HIGH );
- i2c_delay( TSUSTO );
-
- /* Set SCL=1, SDA=1 */
- i2c_set_sda( SDA_HIGH );
- i2c_delay( TBUF );
-
- i2c_sda_dir_in();
-
- if ( !i2c_sda_is_high() || !i2c_scl_is_high() )
- {
- printk( KERN_DEBUG "I2C: EI2CSTOPCOND\n" );
- return ( EI2CSTOPCOND );
- }
-
- return ( EI2CNOERRORS );
-} /* i2c_stop */
-
-
-/*#---------------------------------------------------------------------------
- *#
- *# FUNCTION NAME: i2c_outbyte
- *#
- *# DESCRIPTION : write a byte to the i2c interface
- *#
- *# PARAMETERS : x: byte to be sent on the I2C bus
- *#
- *# RETURN : none
- *#
- *#---------------------------------------------------------------------------
- */
-int i2c_outbyte( unsigned char x )
-{
- int i;
-
- i2c_sda_dir_out();
-
- for ( i = 0; i < 8; i++ )
- {
- if ( x & 0x80 )
- {
- i2c_set_sda( SDA_HIGH );
- }
- else
- {
- i2c_set_sda( SDA_LOW );
- }
-
- i2c_delay( TSUDAT );
- i2c_set_scl( SCL_HIGH );
- i2c_delay( THIGH );
- i2c_set_scl( SCL_LOW );
- i2c_delay( TSUDAT );
- i2c_set_sda( SDA_LOW );
- /* There should be only 5 us between falling edge and new rising
- * edge of clock pulse.
- * Since we spend already 1 us since clock edge was low, there are
- * only ( TLOW - TSUDAT ) us left.
- * Next to this, since the data line will be set up 1 us before the
- * clock line is set up, we can reduce the delay with another us.
- */
- i2c_delay( TLOW - TSUDAT - WAITONEUS );
- x <<= 1;
- }
-
- /* enable input */
- i2c_sda_dir_in();
-
- if ( !i2c_getack() )
- {
- printk( KERN_DEBUG "I2C: EI2CNOACKNLD\n" );
- return( EI2CNOACKNLD );
- }
-
- return ( EI2CNOERRORS );
-} /* i2c_outbyte */
-
-
-/*#---------------------------------------------------------------------------
- *#
- *# FUNCTION NAME: i2c_inbyte
- *#
- *# DESCRIPTION : read a byte from the i2c interface
- *#
- *# PARAMETERS : none
- *#
- *# RETURN : returns the byte read from the I2C device
- *#
- *#---------------------------------------------------------------------------
- */
-unsigned char i2c_inbyte( void )
-{
- unsigned char aBitByte = 0;
- unsigned char Mask = 0x80; /* !!! ATTENTION: do NOT use 'char', otherwise shifting is wrong!!! */
- /* Must be UNSIGNED, not SIGNED! */
-
-
- /* Switch off I2C to get bit */
- i2c_disable();
- i2c_sda_dir_in();
-
- while ( Mask != 0 )
- {
- i2c_set_scl( SCL_HIGH );
- i2c_delay( THIGH );
-
- if ( i2c_sda_is_high() )
- {
- aBitByte |= Mask;
- }
-
- i2c_set_scl( SCL_LOW );
-
- Mask >>= 1;
-
- i2c_delay( TLOW );
- }
-
- /*
- * we leave the clock low, getbyte is usually followed
- * by sendack/nack, they assume the clock to be low
- */
- return ( aBitByte );
-} /* i2c_inbyte */
-
-
-/*#---------------------------------------------------------------------------
- *#
- *# FUNCTION NAME: i2c_getack
- *#
- *# DESCRIPTION : checks if ack was received from ic2
- *#
- *# PARAMETERS : none
- *#
- *# RETURN : returns the ack state of the I2C device
- *#
- *#---------------------------------------------------------------------------
- */
-int i2c_getack( void )
-{
- int ack = 1;
-
- /* generate ACK clock pulse */
- i2c_set_scl( SCL_HIGH );
-
- /* switch off I2C */
- i2c_disable();
-
- /* now wait for ack */
- i2c_delay( THIGH );
- /* check for ack: if SDA is high, then NACK, else ACK */
- if ( i2c_sda_is_high() )
- {
- ack = 0;
- }
- else
- {
- ack = 1;
- }
-
- /* end clock pulse */
- i2c_enable();
- i2c_set_scl( SCL_LOW );
- i2c_sda_dir_out();
- i2c_set_sda( SDA_LOW );
-
- /* Since we "lost" already THDDAT time, we can subtract it here... */
- i2c_delay( TLOW - THDDAT );
-
- return ( ack );
-} /* i2c_getack */
-
-
-/*#---------------------------------------------------------------------------
- *#
- *# FUNCTION NAME: i2c_sendack
- *#
- *# DESCRIPTION : sends ACK on received data
- *#
- *# PARAMETERS : none
- *#
- *# RETURN : none
- *#
- *#---------------------------------------------------------------------------
- */
-void i2c_sendack( void )
-{
- /* enable output */
- /* Clock has been set to TLOW already at end of i2c_inbyte()
- * and i2c_outbyte(), so no need to do it again.
- */
- i2c_sda_dir_out();
- /* set ack pulse low */
- i2c_set_sda( SDA_LOW );
- /* generate clock pulse */
- i2c_delay( TSUDAT );
- i2c_set_scl( SCL_HIGH );
- i2c_delay( THIGH );
- i2c_set_scl( SCL_LOW );
- i2c_delay( THDDAT );
- /* reset data out */
- i2c_set_sda( SDA_HIGH );
- /* Subtract time spend already when waited to put SDA high */
- i2c_delay( TLOW - THDDAT );
-
- /* release the SDA line */
- i2c_sda_dir_in();
-} /* i2c_sendack */
-
-
-/*#---------------------------------------------------------------------------
- *#
- *# FUNCTION NAME: i2c_sendnack
- *#
- *# DESCRIPTION : sends NACK on received data
- *#
- *# PARAMETERS : none
- *#
- *# RETURN : none
- *#
- *#---------------------------------------------------------------------------
- */
-void i2c_sendnack( void )
-{
- /* 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.
- */
- /* set data high */
- i2c_set_sda( SDA_HIGH );
- /* enable output */
- i2c_sda_dir_out();
-
- /* generate clock pulse */
- i2c_delay( TSUDAT );
- i2c_set_scl( SCL_HIGH );
- i2c_delay( THIGH );
- i2c_set_scl( SCL_LOW );
- i2c_delay( TSUDAT );
- i2c_set_sda( SDA_LOW );
- i2c_delay( TLOW - TSUDAT );
-
- /* There's no need to change the direction of SDA to "in" again,
- * since a NACK is always followed by a stop condition.
- * A STOP condition will put the direction of SDA back to "out"
- * resulting in a useless SDA "dip" on the line...
- */
- /* i2c_sda_dir_in(); */
-} /* i2c_sendnack */
-
-
-/*#---------------------------------------------------------------------------
- *#
- *# FUNCTION NAME: i2c_writereg
- *#
- *# DESCRIPTION : writes a value to a register of an I2C device
- *#
- *# PARAMETERS : theSlave = slave address of the I2C device
- *# theReg = register of the I2C device that needs to be written
- *# theValue = value to be written to the register
- *#
- *# RETURN : returns OR-ed result of the write action:
- *# 0 = Ok
- *# 1 = Slave_NoAck
- *# 2 = Reg_NoAck
- *# 4 = Val_NoAck
- *#
- *#---------------------------------------------------------------------------
- */
-int i2c_writereg( unsigned char theSlave
- , unsigned char theReg
- , unsigned char theValue
- )
-{
- int error, cntr = 3;
- unsigned long flags;
-
- spin_lock( &i2c_lock );
-
- do
- {
- error = 0;
- /* we don't like to be interrupted */
- local_irq_save( flags );
-
- i2c_start();
- /* send slave address */
- if ( EI2CNOACKNLD == i2c_outbyte( theSlave & 0xfe ) )
- {
- error = 1;
- }
-
- /* now select register */
- if ( EI2CNOACKNLD == i2c_outbyte( theReg ) )
- {
- error |= 2;
- }
-
- /* send register register data */
- if ( EI2CNOACKNLD == i2c_outbyte( theValue ) )
- {
- error |= 4;
- }
-
- /* end byte stream */
- i2c_stop();
- /* enable interrupt again */
- local_irq_restore( flags );
-
- } while ( error && cntr-- );
-
- i2c_delay( TLOW );
-
- spin_unlock( &i2c_lock );
-
- return ( -error );
-} /* i2c_writereg */
-
-
-/*#---------------------------------------------------------------------------
- *#
- *# FUNCTION NAME: i2c_readreg
- *#
- *# DESCRIPTION : reads the value from a certain register of an I2C device.
- *# Function first writes the register that it wants to read
- *# later on.
- *#
- *# PARAMETERS : theSlave = slave address of the I2C device
- *# theReg = register of the I2C device that needs to be written
- *#
- *# RETURN : returns OR-ed result of the write action:
- *# 0 = Ok
- *# 1 = Slave_NoAck
- *# 2 = Reg_NoAck
- *# 4 = Val_NoAck
- *#
- *#---------------------------------------------------------------------------
- */
-unsigned char i2c_readreg( unsigned char theSlave
- , unsigned char theReg
- )
-{
- unsigned char b = 0;
- int error, cntr = 3;
- unsigned long flags;
-
- spin_lock( &i2c_lock );
-
- do
- {
- error = 0;
-
- /* we don't like to be interrupted */
- local_irq_save( flags );
-
- /* generate start condition */
- i2c_start();
-
- /* send slave address */
- if ( EI2CNOACKNLD == i2c_outbyte( theSlave & 0xfe ) )
- {
- error = 1;
- }
-
- /* now select register */
- i2c_sda_dir_out();
-
- if ( EI2CNOACKNLD == i2c_outbyte( theReg ) )
- {
- error |= 2;
- }
-
- /* repeat start condition */
- i2c_delay( TLOW );
- i2c_start();
-
- /* send slave address */
- if ( EI2CNOACKNLD == i2c_outbyte( theSlave | 0x01 ) )
- {
- error |= 1;
- }
-
- /* fetch register */
- b = i2c_inbyte();
- /*
- * last received byte needs to be nacked
- * instead of acked
- */
- i2c_sendnack();
-
- /* end sequence */
- i2c_stop();
-
- /* enable interrupt again */
- local_irq_restore( flags );
-
- } while ( error && cntr-- );
-
- spin_unlock( &i2c_lock );
-
- return ( b );
-} /* i2c_readreg */
-
-
-/*#---------------------------------------------------------------------------
- *#
- *# FUNCTION NAME: i2c_read
- *#
- *# DESCRIPTION :
- *#
- *# PARAMETERS :
- *#
- *# RETURN :
- *#
- *#---------------------------------------------------------------------------
- */
-int i2c_read( unsigned char slave, unsigned char* rbuf, unsigned char rlen )
-{
- return ( i2c_command( slave, NULL, 0, rbuf, rlen ) );
-} /* i2c_read */
-
-
-/*#---------------------------------------------------------------------------
- *#
- *# FUNCTION NAME: i2c_write
- *#
- *# DESCRIPTION :
- *#
- *# PARAMETERS :
- *#
- *# RETURN :
- *#
- *#---------------------------------------------------------------------------
- */
-int i2c_write( unsigned char slave, unsigned char* wbuf, unsigned char wlen )
-{
- return ( i2c_command( slave, wbuf, wlen, NULL, 0 ) );
-} /* i2c_write */
-
-
-/*#---------------------------------------------------------------------------
- *#
- *# FUNCTION NAME: i2c_writeread
- *#
- *# DESCRIPTION :
- *#
- *# PARAMETERS :
- *#
- *# RETURN :
- *#
- *#---------------------------------------------------------------------------
- */
-int i2c_writeread( unsigned char slave
- , unsigned char* wbuf
- , unsigned char wlen
- , unsigned char* rbuf
- , unsigned char rlen
- )
-{
- return ( i2c_command( slave, wbuf, wlen, rbuf, rlen ) );
-} /* i2c_writeread */
-
-
-/*#---------------------------------------------------------------------------
- *#
- *# FUNCTION NAME: module_init
- *#
- *# DESCRIPTION : this makes sure that i2c_register is called during boot
- *#
- *# PARAMETERS :
- *#
- *#---------------------------------------------------------------------------
- */
-module_init( i2c_register );
-
-/****************** END OF FILE i2c.c ********************************/
+/*!***************************************************************************
+*!
+*! FILE NAME : i2c.c
+*!
+*!
+*! ---------------------------------------------------------------------------
+*!
+*! ( C ) Copyright 1999-2002 Axis Communications AB, LUND, SWEDEN
+*!
+*!***************************************************************************/
+
+/******************** INCLUDE FILES SECTION ****************************/
+
+#include <linux/module.h>
+#include <linux/fs.h>
+
+#ifdef CONFIG_ETRAX_I2C_DYN_ALLOC
+#include <linux/types.h> /* for dev_t */
+#include <linux/cdev.h> /* for struct cdev */
+#endif
+
+#include <linux/device.h>
+
+#include "etraxi2c.h"
+
+#include "i2c_errno.h"
+
+#include <asm/io.h>
+#include <asm/delay.h>
+#include <asm/arch/io_interface_mux.h>
+#include <asm/uaccess.h>
+
+#include "i2c_gvc.h"
+
+MODULE_DESCRIPTION( "I2C Device Driver - 2.3" );
+
+/*!*********************************************************************
+ *!History I2C driver Geert Vancompernolle
+ *!---------------------------------------
+ *!
+ *! - v1.0:
+ *! First official version.
+ *!
+ *! - v1.1:
+ *! Changes to remove unwanted spikes at ACK/NACK time.
+ *!
+ *!*********************************************************************/
+
+MODULE_LICENSE( "GPL" );
+
+/****************** MACRO's **********************/
+
+#define D( x )
+
+#ifndef CONFIG_ETRAX_I2C_DYN_ALLOC
+#define I2C_MAJOR 123 /* LOCAL/EXPERIMENTAL */
+#endif
+
+#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 */
+#define THDSTA 4 /* Hold delay time for (repeated) START condition */
+#define TLOW 5 /* LOW period of the SCL clock */
+#define THDDAT 1 /* Hold delay time for DATA: value of 0 is allowed but 1 taken to be sure */
+#define TSUDAT 1 /* Set-up time for DATA */
+#define THIGH 4 /* HIGH period of the SCL clock */
+#define TSUSTA 5 /* Set-up time for a repeated START condition */
+#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 )
+
+#define SCL_HIGH 1
+#define SCL_LOW 0
+#define SDA_HIGH 1
+#define SDA_LOW 0
+
+#ifdef CONFIG_ETRAX_I2C_USES_PB_NOT_PB_I2C
+/* Use PB and not PB_I2C */
+#ifndef CONFIG_ETRAX_I2C_DATA_PORT
+#define CONFIG_ETRAX_I2C_DATA_PORT 0
+#endif
+#ifndef CONFIG_ETRAX_I2C_CLK_PORT
+#define CONFIG_ETRAX_I2C_CLK_PORT 1
+#endif
+
+#define SDABIT CONFIG_ETRAX_I2C_DATA_PORT
+#define SCLBIT CONFIG_ETRAX_I2C_CLK_PORT
+#define i2c_enable()
+#define i2c_disable()
+
+/* enable or disable output-enable, to select output or input on the i2c bus */
+#define i2c_sda_dir_out() \
+ REG_SHADOW_SET( R_PORT_PB_DIR, port_pb_dir_shadow, SDABIT, 1 )
+#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 )
+#define i2c_set_sda( x ) \
+ REG_SHADOW_SET( R_PORT_PB_DATA, port_pb_data_shadow, SDABIT, x )
+
+/* read status of SDA bit from the i2c interface */
+#define i2c_sda_is_high() ( ( ( *R_PORT_PB_READ & ( 1 << SDABIT ) ) ) >> SDABIT )
+
+/* read status of SCL bit from the i2c interface */
+#define i2c_scl_is_high() ( ( ( *R_PORT_PB_READ & ( 1 << SCLBIT ) ) ) >> SCLBIT )
+
+#else
+/* enable or disable the i2c interface */
+#define i2c_enable() *R_PORT_PB_I2C = ( port_pb_i2c_shadow |= IO_MASK( R_PORT_PB_I2C, i2c_en ) )
+#define i2c_disable() *R_PORT_PB_I2C = ( port_pb_i2c_shadow &= ~IO_MASK( R_PORT_PB_I2C, i2c_en ) )
+
+/* enable or disable output-enable, to select output or input on the i2c bus */
+#define i2c_sda_dir_out() \
+ *R_PORT_PB_I2C = ( port_pb_i2c_shadow &= ~IO_MASK( R_PORT_PB_I2C, i2c_oe_ ) ); \
+ REG_SHADOW_SET( R_PORT_PB_DIR, port_pb_dir_shadow, 0, 1 );
+#define i2c_sda_dir_in() \
+ *R_PORT_PB_I2C = ( port_pb_i2c_shadow |= IO_MASK( R_PORT_PB_I2C, i2c_oe_ ) ); \
+ REG_SHADOW_SET( R_PORT_PB_DIR, port_pb_dir_shadow, 0, 0 );
+
+/* control the i2c clock and data signals */
+#define i2c_set_scl( x ) \
+ *R_PORT_PB_I2C = ( port_pb_i2c_shadow = ( port_pb_i2c_shadow & \
+ ~IO_MASK( R_PORT_PB_I2C, i2c_set_scl ) ) | IO_FIELD( R_PORT_PB_I2C, i2c_set_scl, ( x ) ) ); \
+ REG_SHADOW_SET( R_PORT_PB_DATA, port_pb_data_shadow, 1, x );
+
+#define i2c_set_sda( x ) \
+ *R_PORT_PB_I2C = ( port_pb_i2c_shadow = ( port_pb_i2c_shadow & \
+ ~IO_MASK( R_PORT_PB_I2C, i2c_d ) ) | IO_FIELD( R_PORT_PB_I2C, i2c_d, ( x ) ) ); \
+ REG_SHADOW_SET( R_PORT_PB_DATA, port_pb_data_shadow, 0, x );
+
+/* read a bit from the i2c interface */
+#define i2c_sda_is_high() ( *R_PORT_PB_READ & 0x1 )
+#endif
+
+/* use the kernels delay routine */
+#define i2c_delay( usecs ) udelay( usecs )
+
+
+/****************** TYPEDEF's **********************/
+
+
+/****************** STATIC (file scope) VARIABLES **********************/
+static DEFINE_SPINLOCK( i2c_lock ); /* Protect directions etc */
+static const char i2c_name[] = "i2c";
+
+
+
+/****************** PROTOTYPING SECTION *************************/
+static int i2c_open( struct inode *inode, struct file *filp );
+static int i2c_release( struct inode *inode, struct file *filp );
+static int i2c_command( unsigned char slave
+ , unsigned char* wbuf
+ , unsigned char wlen
+ , unsigned char* rbuf
+ , unsigned char rlen
+ );
+static int i2c_bus_free_check( unsigned char maxretries );
+static void i2c_finalise( const char* text, unsigned long irqflags );
+
+
+/************************************************************************/
+/****************** AUXILIARIES *************************/
+/************************************************************************/
+
+/*#---------------------------------------------------------------------------
+ *#
+ *# FUNCTION NAME: i2c_open
+ *#
+ *# DESCRIPTION : opens an I2C device
+ *#
+ *# PARAMETERS : *inode: reference to inode
+ *# *filp : reference to file pointer
+ *#
+ *#---------------------------------------------------------------------------
+ */
+static int i2c_open( struct inode *inode, struct file *filp )
+{
+ return 0;
+} /* i2c_open */
+
+
+/*#---------------------------------------------------------------------------
+ *#
+ *# FUNCTION NAME: i2c_release
+ *#
+ *# DESCRIPTION : Releases the I2C device
+ *#
+ *# PARAMETERS : *inode: reference to inode
+ *# *filp : reference to file pointer
+ *#
+ *#---------------------------------------------------------------------------
+ */
+static int i2c_release( struct inode *inode, struct file *filp )
+{
+ return 0;
+} /* i2c_release */
+
+
+/*#---------------------------------------------------------------------------
+ *#
+ *# FUNCTION NAME: i2c_ioctl
+ *#
+ *# DESCRIPTION : Main device API: ioctl's to write/read
+ *# to/from i2c registers
+ *#
+ *# PARAMETERS : *inode: reference to inode
+ *# *filp : reference to file pointer
+ *# cmd : command to be executed during the ioctl call
+ *# arg : pointer to a structure with the data???
+ *#
+ *# RETURN : result of the ioctl call
+ *#
+ *#---------------------------------------------------------------------------
+ */
+static int i2c_ioctl( struct inode *inode
+ , struct file *file
+ , unsigned int cmd
+ , unsigned long arg
+ )
+{
+ /* the acme ioctls */
+ I2C_DATA i2cdata;
+ int RetVal = EI2CNOERRORS;
+
+ if ( _IOC_TYPE( cmd ) != ETRAXI2C_IOCTYPE )
+ {
+ return ( -EINVAL );
+ }
+
+ switch ( _IOC_NR( cmd ) )
+ {
+ case I2C_WRITEREG:
+ /* write to an i2c slave */
+ RetVal = i2c_writereg( I2C_ARGSLAVE( arg )
+ , I2C_ARGREG( arg )
+ , I2C_ARGVALUE( arg )
+ );
+ break;
+
+ case I2C_READREG:
+ RetVal = i2c_readreg( I2C_ARGSLAVE( arg ), I2C_ARGREG( arg ) );
+ break;
+
+ /* New functions added by GVC */
+ case I2C_READ:
+ copy_from_user( (char*)&i2cdata, (char*)arg, sizeof( I2C_DATA ) );
+ {
+ int RetryCntr = MAXRETRIES;
+
+ do
+ {
+ RetVal = i2c_command( i2cdata.slave
+ , NULL
+ , 0
+ , i2cdata.rbuf
+ , i2cdata.rlen
+ );
+ } while ( ( EI2CNOERRORS != RetVal )
+ &&( --RetryCntr )
+ );
+ }
+ copy_to_user( (char*)arg, (char*)&i2cdata, sizeof( I2C_DATA ) );
+ break;
+
+ case I2C_WRITE:
+ copy_from_user( (char*)&i2cdata, (char*)arg, sizeof( I2C_DATA ) );
+ {
+ int RetryCntr = MAXRETRIES;
+
+ do
+ {
+ RetVal = i2c_command( i2cdata.slave
+ , i2cdata.wbuf
+ , i2cdata.wlen
+ , NULL
+ , 0
+ );
+ } while ( ( EI2CNOERRORS != RetVal )
+ &&( --RetryCntr )
+ );
+ }
+ break;
+
+ case I2C_WRITEREAD:
+ copy_from_user( (char*)&i2cdata, (char*)arg, sizeof( I2C_DATA ) );
+ {
+ int RetryCntr = MAXRETRIES;
+
+ do
+ {
+ RetVal = i2c_command( i2cdata.slave
+ , i2cdata.wbuf
+ , i2cdata.wlen
+ , i2cdata.rbuf
+ , i2cdata.rlen
+ );
+ } while ( ( EI2CNOERRORS != RetVal )
+ &&( --RetryCntr )
+ );
+ }
+ copy_to_user( (char*)arg, (char*)&i2cdata, sizeof( I2C_DATA ) );
+ break;
+
+ default:
+ RetVal = -EINVAL;
+ }
+
+ return ( -RetVal );
+} /* i2c_ioctl */
+
+
+/*#---------------------------------------------------------------------------
+ *#
+ *# FUNCTION NAME: i2c_command
+ *#
+ *# DESCRIPTION : general routine to read/write bytes from an I2C device
+ *#
+ *# 'i2c_command()' sends wlen bytes to the I2c bus and receives
+ *# rlen bytes from the I2c bus.
+ *# The data to be send must be placed in wbuf[ 0 ] upto wbuf[ wlen - 1 ).
+ *# The data to be received is assembled in rbuf[ 0 ] upto rbuf[ rlen - 1 ].
+ *#
+ *# If no data is to be sent or received, put appropriate buffer parameter
+ *# to "NULL" and appropriate length parameter to "0".
+ *#
+ *# PARAMETERS : slave = slave address of the I2C device
+ *# wbuf = address of first element of write buffer (wbuf)
+ *# wlen = number of bytes to be written to slave
+ *# rbuf = address of first element of read buffer (rbuf)
+ *# rlen = number of bytes to be read from slave
+ *#
+ *# RETURN :
+ *# EI2CNOERRORS: I2C communication went fine
+ *# EI2CBUSNFREE: I2C bus is not free
+ *# EI2CWADDRESS: I2C write address failed
+ *# EI2CRADDRESS: I2C read address failed
+ *# EI2CSENDDATA: I2C send data failed
+ *# EI2CRECVDATA: I2C receive data failed
+ *# EI2CSTRTCOND: I2C start condition failed
+ *# EI2CRSTACOND: I2C repeated start condition failed
+ *# EI2CSTOPCOND: I2C stop condition failed
+ *# EI2CNOSNDBYT: I2C no bytes to be sent
+ *# EI2CNOSNDBUF: I2C no send buffer defined
+ *# EI2CNORCVBYT: I2C no bytes to be received
+ *# EI2CNORCVBUF: I2C no receive buffer defined
+ *# EI2CNOACKNLD: I2C no acknowledge received
+ *#
+ *# REMARK :
+ *# First, the send part is completed.
+ *# In the send routine, there is no stop generated. This is because maybe
+ *# a repeated start condition must be generated.
+ *# This happens when we want to receive some data from the I2c bus. If not,
+ *# at the end of the general I2c loop the stopcondition is generated.
+ *# If, on the contrary, there are a number of bytes to be received, a new
+ *# startcondition is generated in the 'if' part of the main I2c routine,
+ *# which controls the receiving part.
+ *# Only when the receiving of data is finished, a final stopcondition is
+ *# generated.
+ *#
+ *#---------------------------------------------------------------------------
+ */
+static int i2c_command( unsigned char slave
+ , unsigned char* wbuf
+ , unsigned char wlen
+ , unsigned char* rbuf
+ , unsigned char rlen
+ )
+{
+ /* Check arguments and report error if relevant... */
+ if ( ( wlen > 0 ) && ( wbuf == NULL ) )
+ {
+ printk( KERN_DEBUG "I2C: EI2CNOSNDBUF\n" );
+ return ( EI2CNOSNDBUF );
+ }
+ else if ( ( wlen == 0 ) && ( wbuf != NULL ) )
+ {
+ printk( KERN_DEBUG "I2C: EI2CNOSNDBYT\n" );
+ return ( EI2CNOSNDBYT );
+ }
+ else if ( ( rlen > 0 ) && ( rbuf == NULL ) )
+ {
+ printk( KERN_DEBUG "I2C: EI2CNORCVBUF\n" );
+ return ( EI2CNORCVBUF );
+ }
+ else if ( ( rlen == 0 ) && ( rbuf != NULL ) )
+ {
+ printk( KERN_DEBUG "I2C: EI2CNORCVBYT\n" );
+ return ( EI2CNORCVBYT );
+ }
+ else if ( EI2CBUSNFREE == i2c_bus_free_check( MAXBUSFREERETRIES ) )
+ {
+ /* There's no need to try more, since we weren't even
+ * able to start the I2C communication.
+ * So, no IRQ flags are stored yet, no changes to any other
+ * stuff like START, STOP, SENDBYTES...
+ * Result, simply write down the error and return the correct error code.
+ */
+ printk( KERN_DEBUG "I2C: EI2CBUSNFREE\n" );
+ return ( EI2CBUSNFREE );
+ }
+ else
+ {
+ /* Finally... We made it... */
+ unsigned long irqflags = 0;
+
+ /* we don't like to be interrupted */
+ local_irq_save( irqflags );
+
+ /* Check if there are bytes to be send,
+ * or if you immediately want to receive data.
+ */
+ if ( 0 < wlen )
+ {
+ /* start I2C communication */
+ if ( EI2CNOERRORS != i2c_start() )
+ {
+ return ( i2c_finalise( "I2C: EI2CSTRTCOND\n", irqflags )
+ , EI2CSTRTCOND
+ );
+ }
+
+ /* send slave address: xxxxxxx0B (last bit must be zero) */
+ if ( EI2CNOERRORS != i2c_outbyte( slave & WRITEADDRESS_MASK ) )
+ {
+ return ( i2c_finalise( "I2C: EI2CWADDRESS\n", irqflags )
+ , EI2CWADDRESS
+ );
+ }
+
+ while ( wlen-- )
+ {
+ /* send register data */
+ if ( EI2CNOERRORS != i2c_outbyte( *wbuf ) && wlen )
+ {
+ return ( i2c_finalise( "I2C: EI2CSENDDATA\n", irqflags )
+ , EI2CSENDDATA
+ );
+ }
+
+ wbuf++;
+ };
+
+ i2c_delay( TLOW );
+ }
+
+ /*
+ * Receiving data from I2c_bus
+ * If there are bytes to be received, a new start condition is
+ * generated => Repeated Startcondition.
+ * A final stopcondition is generated at the end of the main I2c
+ * routine.
+ */
+ if ( 0 < rlen )
+ {
+ /*
+ * Generate start condition if wlen == 0
+ * or repeated start condition if wlen != 0...
+ */
+ if ( EI2CNOERRORS != i2c_start() )
+ {
+ return ( i2c_finalise( ( ( 0 < wlen )
+ ? "I2C: EI2CRSTACOND\n"
+ : "I2C: EI2CSTRTCOND\n"
+ )
+ , irqflags
+ )
+ , ( ( 0 < wlen ) ? EI2CRSTACOND : EI2CSTRTCOND )
+ );
+ }
+
+ /* Send ReadAddress: xxxxxxx1B (last bit must be one) */
+ if ( EI2CNOERRORS != i2c_outbyte( slave | READADDRESS_MASK ) )
+ {
+ return ( i2c_finalise( "I2C: EI2CRADDRESS\n", irqflags )
+ , EI2CRADDRESS
+ );
+ }
+
+ while ( rlen-- )
+ {
+ /* fetch register */
+ *rbuf = i2c_inbyte();
+ rbuf++;
+
+ /* last received byte needs to be NACK-ed instead of ACK-ed */
+ if ( rlen )
+ {
+ i2c_sendack();
+ }
+ else
+ {
+ i2c_sendnack();
+ }
+ };
+ }
+
+ /* Generate final stop condition */
+ if ( EI2CNOERRORS != i2c_stop() )
+ {
+ return ( i2c_finalise( "I2C CMD: EI2CSTOPCOND\n", irqflags )
+ , EI2CSTOPCOND
+ );
+ }
+
+ /* enable interrupt again */
+ local_irq_restore( irqflags );
+ }
+
+ return ( EI2CNOERRORS );
+} /* i2c_command */
+
+
+/*#---------------------------------------------------------------------------
+ *#
+ *# FUNCTION NAME: i2c_bus_free_check
+ *#
+ *# DESCRIPTION : checks if the I2C bus is free before starting
+ *# an I2C communication
+ *#
+ *# PARAMETERS : maxretries, the number of times we will try to release
+ *# the I2C bus
+ *#
+ *# RETURN : I2cStatus_I2cBusNotFreeError in case the bus is not free,
+ *# I2cStatus_I2cNoError otherwise
+ *#
+ *#---------------------------------------------------------------------------
+ */
+static int i2c_bus_free_check( unsigned char maxretries )
+{
+ i2c_sda_dir_in(); /* Release SDA line */
+ i2c_set_scl( SCL_HIGH ); /* put SCL line high */
+
+ i2c_delay( WAITONEUS );
+
+ while ( ( !i2c_sda_is_high() || !i2c_scl_is_high() )
+ &&( maxretries-- )
+ )
+ {
+ /* Try to release I2C bus by generating STOP conditions */
+ i2c_stop();
+ }
+
+ if ( 0 == maxretries )
+ {
+ printk( KERN_DEBUG "I2C: EI2CBUSNFREE\n" );
+ return ( EI2CBUSNFREE );
+ }
+ else
+ {
+ return ( EI2CNOERRORS );
+ }
+} /* i2c_bus_free_check */
+
+
+static void i2c_finalise( const char* errortxt
+ , unsigned long irqflags
+ )
+{
+ printk( KERN_DEBUG "%s", errortxt );
+ local_irq_restore( irqflags );
+ /* The least we can do when things go terribly wrong,
+ * is to try to release the bus.
+ * If this fails, well, then I don't know
+ * what I can do more for the moment...
+ */
+ (void)i2c_bus_free_check( MAXBUSFREERETRIES );
+} /* i2c_finalise */
+
+
+static struct file_operations i2c_fops =
+{
+ .owner = THIS_MODULE
+, .ioctl = i2c_ioctl
+, .open = i2c_open
+, .release = i2c_release
+};
+
+
+/***********************************************************************/
+/************* EXTERNAL FUNCTION DEFINITION SECTION ********************/
+/***********************************************************************/
+
+/*#---------------------------------------------------------------------------
+ *#
+ *# FUNCTION NAME: i2c_init
+ *#
+ *# DESCRIPTION : initialises the I2C device driver
+ *#
+ *# PARAMETERS :
+ *#
+ *#---------------------------------------------------------------------------
+ */
+int __init i2c_init( void )
+{
+ static int res = 0;
+ static int first = 1;
+
+ if ( !first )
+ {
+ return res;
+ }
+
+ first = 0;
+
+ /* Setup and enable the Port B I2C interface */
+
+#ifndef CONFIG_ETRAX_I2C_USES_PB_NOT_PB_I2C
+ /* here, we're using the dedicated I2C pins of FoxBoard */
+ if ( ( res = cris_request_io_interface( if_i2c, "I2C" ) ) )
+ {
+ printk( KERN_CRIT "i2c_init: Failed to get IO interface\n" );
+ return res;
+ }
+
+ *R_PORT_PB_I2C = port_pb_i2c_shadow |=
+ IO_STATE( R_PORT_PB_I2C, i2c_en, on ) |
+ IO_FIELD( R_PORT_PB_I2C, i2c_d, 1 ) |
+ IO_FIELD( R_PORT_PB_I2C, i2c_set_scl, 1 ) |
+ IO_STATE( R_PORT_PB_I2C, i2c_oe_, enable );
+
+ port_pb_dir_shadow &= ~IO_MASK( R_PORT_PB_DIR, dir0 );
+ port_pb_dir_shadow &= ~IO_MASK( R_PORT_PB_DIR, dir1 );
+
+ *R_PORT_PB_DIR = ( port_pb_dir_shadow |=
+ IO_STATE( R_PORT_PB_DIR, dir0, input ) |
+ IO_STATE( R_PORT_PB_DIR, dir1, output ) );
+#else
+ /* If everything goes fine, res = 0, meaning "if" fails =>
+ * will do the "else" too and as such initialise the clock port...
+ * Clever trick!
+ */
+ if ( ( res = cris_io_interface_allocate_pins( if_i2c
+ , 'b'
+ , CONFIG_ETRAX_I2C_DATA_PORT
+ , CONFIG_ETRAX_I2C_DATA_PORT
+ )
+ )
+ )
+ {
+ printk( KERN_WARNING "i2c_init: Failed to get IO pin for I2C data port\n" );
+ return ( res );
+ }
+ /* Same here...*/
+ else if ( ( res = cris_io_interface_allocate_pins( if_i2c
+ , 'b'
+ , CONFIG_ETRAX_I2C_CLK_PORT
+ , CONFIG_ETRAX_I2C_CLK_PORT
+ )
+ )
+ )
+ {
+ cris_io_interface_free_pins( if_i2c
+ , 'b'
+ , CONFIG_ETRAX_I2C_DATA_PORT
+ , CONFIG_ETRAX_I2C_DATA_PORT
+ );
+ printk( KERN_WARNING "i2c_init: Failed to get IO pin for I2C clk port\n" );
+ }
+#endif
+
+ return ( res );
+} /* i2c_init */
+
+
+/*#---------------------------------------------------------------------------
+ *#
+ *# FUNCTION NAME: i2c_register
+ *#
+ *# DESCRIPTION : this registers the i2c driver as a character device
+ *#
+ *# PARAMETERS :
+ *#
+ *#---------------------------------------------------------------------------
+ */
+
+static struct class *i2c_class;
+
+static int __init i2c_register( void )
+{
+ int res;
+#ifdef CONFIG_ETRAX_I2C_DYN_ALLOC
+ dev_t devt;
+ struct cdev *my_i2cdev = NULL;
+#endif
+
+ res = i2c_init();
+
+ if ( res < 0 )
+ {
+ return res;
+ }
+
+#ifdef CONFIG_ETRAX_I2C_DYN_ALLOC
+ res = alloc_chrdev_region( &devt, 0, 1, i2c_name );
+
+ if ( res < 0 )
+ {
+ printk( KERN_DEBUG "I2C: EI2CNOMNUMBR\n" );
+ return ( res );
+ }
+
+ my_i2cdev = cdev_alloc();
+ my_i2cdev->ops = &i2c_fops;
+ my_i2cdev->owner = THIS_MODULE;
+
+ /* make device "alive" */
+ res = cdev_add( my_i2cdev, devt, 1 );
+
+ if ( res < 0 )
+ {
+ printk( KERN_DEBUG "I2C: EI2CDADDFAIL\n" );
+ return ( res );
+ }
+
+ int i2c_major = MAJOR( devt );
+#else
+ res = register_chrdev( I2C_MAJOR, i2c_name, &i2c_fops );
+
+ if ( res < 0 )
+ {
+ printk( KERN_ERR "i2c: couldn't get a major number.\n" );
+ return res;
+ }
+
+ int i2c_major = I2C_MAJOR;
+#endif
+
+ 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 CONFIG_ETRAX_I2C_SLAVE_DELAY
+ printk( KERN_INFO "I2C: with master/slave delay patch\n" );
+#endif
+
+ i2c_class = class_create (THIS_MODULE, "i2c_etrax");
+ device_create (i2c_class, NULL,
+ MKDEV(i2c_major,0), NULL, i2c_name);
+
+ return ( 0 );
+} /* i2c_register */
+
+
+/*#---------------------------------------------------------------------------
+ *#
+ *# FUNCTION NAME: i2c_start
+ *#
+ *# DESCRIPTION : generate i2c start condition
+ *#
+ *# PARAMETERS : none
+ *#
+ *# RETURN : EI2CNOERRORS if OK, EI2CSTRTCOND otherwise
+ *#
+ *#---------------------------------------------------------------------------
+ */
+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() )
+ {
+ printk( KERN_DEBUG "I2C: EI2CSTRTCOND\n" );
+ return ( EI2CSTRTCOND );
+ }
+
+ return ( EI2CNOERRORS );
+} /* i2c_start */
+
+
+/*#---------------------------------------------------------------------------
+ *#
+ *# FUNCTION NAME: i2c_stop
+ *#
+ *# DESCRIPTION : generate i2c stop condition
+ *#
+ *# PARAMETERS : none
+ *#
+ *# RETURN : none
+ *#
+ *#---------------------------------------------------------------------------
+ */
+int i2c_stop( void )
+{
+#ifdef CONFIG_ETRAX_I2C_SLAVE_DELAY
+ int n=MAXSCLRETRIES;
+#endif
+ i2c_sda_dir_out();
+
+ /* Set SCL=0, SDA=0 */
+ /* Don't change order, otherwise you might generate a start condition! */
+ i2c_set_scl( SCL_LOW );
+ i2c_delay( WAITONEUS );
+ i2c_set_sda( SDA_LOW );
+ 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 */
+ i2c_set_sda( SDA_HIGH );
+ i2c_delay( TBUF );
+
+ i2c_sda_dir_in();
+
+ if ( !i2c_sda_is_high() || !i2c_scl_is_high() )
+ {
+ return ( EI2CSTOPCOND );
+ }
+
+ return ( EI2CNOERRORS );
+} /* i2c_stop */
+
+
+/*#---------------------------------------------------------------------------
+ *#
+ *# FUNCTION NAME: i2c_outbyte
+ *#
+ *# DESCRIPTION : write a byte to the i2c interface
+ *#
+ *# PARAMETERS : x: byte to be sent on the I2C bus
+ *#
+ *# RETURN : none
+ *#
+ *#---------------------------------------------------------------------------
+ */
+int i2c_outbyte( unsigned char x )
+{
+ int i;
+
+ i2c_sda_dir_out();
+
+ for ( i = 0; i < 8; i++ )
+ {
+ if ( x & 0x80 )
+ {
+ i2c_set_sda( SDA_HIGH );
+ }
+ else
+ {
+ i2c_set_sda( SDA_LOW );
+ }
+
+ i2c_delay( TSUDAT );
+ i2c_set_scl( SCL_HIGH );
+ i2c_delay( THIGH );
+ i2c_set_scl( SCL_LOW );
+ i2c_delay( TSUDAT );
+ i2c_set_sda( SDA_LOW );
+ /* There should be only 5 us between falling edge and new rising
+ * edge of clock pulse.
+ * Since we spend already 1 us since clock edge was low, there are
+ * only ( TLOW - TSUDAT ) us left.
+ * Next to this, since the data line will be set up 1 us before the
+ * clock line is set up, we can reduce the delay with another us.
+ */
+ i2c_delay( TLOW - TSUDAT - WAITONEUS );
+ x <<= 1;
+ }
+
+ /* enable input */
+ i2c_sda_dir_in();
+
+ if ( !i2c_getack() )
+ {
+ return( EI2CNOACKNLD );
+ }
+
+ return ( EI2CNOERRORS );
+} /* i2c_outbyte */
+
+
+/*#---------------------------------------------------------------------------
+ *#
+ *# FUNCTION NAME: i2c_inbyte
+ *#
+ *# DESCRIPTION : read a byte from the i2c interface
+ *#
+ *# PARAMETERS : none
+ *#
+ *# RETURN : returns the byte read from the I2C device
+ *#
+ *#---------------------------------------------------------------------------
+ */
+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! */
+
+
+ /* Switch off I2C to get bit */
+ i2c_disable();
+ i2c_sda_dir_in();
+
+ 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() )
+ {
+ aBitByte |= Mask;
+ }
+
+ i2c_set_scl( SCL_LOW );
+
+ Mask >>= 1;
+
+ i2c_delay( TLOW );
+ }
+
+ /*
+ * we leave the clock low, getbyte is usually followed
+ * by sendack/nack, they assume the clock to be low
+ */
+ return ( aBitByte );
+} /* i2c_inbyte */
+
+
+/*#---------------------------------------------------------------------------
+ *#
+ *# FUNCTION NAME: i2c_getack
+ *#
+ *# DESCRIPTION : checks if ack was received from ic2
+ *#
+ *# PARAMETERS : none
+ *#
+ *# RETURN : returns the ack state of the I2C device
+ *#
+ *#---------------------------------------------------------------------------
+ */
+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 );
+
+ /* 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() )
+ {
+ ack = 0;
+ }
+ else
+ {
+ ack = 1;
+ }
+
+ /* end clock pulse */
+ i2c_enable();
+ i2c_set_scl( SCL_LOW );
+ i2c_sda_dir_out();
+ i2c_set_sda( SDA_LOW );
+
+ /* Since we "lost" already THDDAT time, we can subtract it here... */
+ i2c_delay( TLOW - THDDAT );
+
+ return ( ack );
+} /* i2c_getack */
+
+
+/*#---------------------------------------------------------------------------
+ *#
+ *# FUNCTION NAME: i2c_sendack
+ *#
+ *# DESCRIPTION : sends ACK on received data
+ *#
+ *# PARAMETERS : none
+ *#
+ *# RETURN : none
+ *#
+ *#---------------------------------------------------------------------------
+ */
+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.
+ */
+ i2c_sda_dir_out();
+ /* set ack pulse low */
+ 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 */
+ i2c_set_sda( SDA_HIGH );
+ /* Subtract time spend already when waited to put SDA high */
+ i2c_delay( TLOW - THDDAT );
+
+ /* release the SDA line */
+ i2c_sda_dir_in();
+} /* i2c_sendack */
+
+
+/*#---------------------------------------------------------------------------
+ *#
+ *# FUNCTION NAME: i2c_sendnack
+ *#
+ *# DESCRIPTION : sends NACK on received data
+ *#
+ *# PARAMETERS : none
+ *#
+ *# RETURN : none
+ *#
+ *#---------------------------------------------------------------------------
+ */
+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.
+ */
+ /* set data high */
+ i2c_set_sda( SDA_HIGH );
+ /* enable output */
+ i2c_sda_dir_out();
+
+ /* 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 );
+ i2c_delay( TLOW - TSUDAT );
+
+ /* There's no need to change the direction of SDA to "in" again,
+ * since a NACK is always followed by a stop condition.
+ * A STOP condition will put the direction of SDA back to "out"
+ * resulting in a useless SDA "dip" on the line...
+ */
+ /* i2c_sda_dir_in(); */
+} /* i2c_sendnack */
+
+
+/*#---------------------------------------------------------------------------
+ *#
+ *# FUNCTION NAME: i2c_writereg
+ *#
+ *# DESCRIPTION : writes a value to a register of an I2C device
+ *#
+ *# PARAMETERS : theSlave = slave address of the I2C device
+ *# theReg = register of the I2C device that needs to be written
+ *# theValue = value to be written to the register
+ *#
+ *# RETURN : returns OR-ed result of the write action:
+ *# 0 = Ok
+ *# 1 = Slave_NoAck
+ *# 2 = Reg_NoAck
+ *# 4 = Val_NoAck
+ *#
+ *#---------------------------------------------------------------------------
+ */
+int i2c_writereg( unsigned char theSlave
+ , unsigned char theReg
+ , unsigned char theValue
+ )
+{
+ int error, cntr = 3;
+ unsigned long flags;
+
+ spin_lock( &i2c_lock );
+
+ do
+ {
+ error = 0;
+ /* we don't like to be interrupted */
+ local_irq_save( flags );
+
+ i2c_start();
+ /* send slave address */
+ if ( EI2CNOACKNLD == i2c_outbyte( theSlave & 0xfe ) )
+ {
+ error = 1;
+ }
+
+ /* now select register */
+ if ( EI2CNOACKNLD == i2c_outbyte( theReg ) )
+ {
+ error |= 2;
+ }
+
+ /* send register register data */
+ if ( EI2CNOACKNLD == i2c_outbyte( theValue ) )
+ {
+ error |= 4;
+ }
+
+ /* end byte stream */
+ i2c_stop();
+ /* enable interrupt again */
+ local_irq_restore( flags );
+
+ } while ( error && cntr-- );
+
+ i2c_delay( TLOW );
+
+ spin_unlock( &i2c_lock );
+
+ return ( -error );
+} /* i2c_writereg */
+
+
+/*#---------------------------------------------------------------------------
+ *#
+ *# FUNCTION NAME: i2c_readreg
+ *#
+ *# DESCRIPTION : reads the value from a certain register of an I2C device.
+ *# Function first writes the register that it wants to read
+ *# later on.
+ *#
+ *# PARAMETERS : theSlave = slave address of the I2C device
+ *# theReg = register of the I2C device that needs to be written
+ *#
+ *# RETURN : returns OR-ed result of the write action:
+ *# 0 = Ok
+ *# 1 = Slave_NoAck
+ *# 2 = Reg_NoAck
+ *# 4 = Val_NoAck
+ *#
+ *#---------------------------------------------------------------------------
+ */
+unsigned char i2c_readreg( unsigned char theSlave
+ , unsigned char theReg
+ )
+{
+ unsigned char b = 0;
+ int error, cntr = 3;
+ unsigned long flags;
+
+ spin_lock( &i2c_lock );
+
+ do
+ {
+ error = 0;
+
+ /* we don't like to be interrupted */
+ local_irq_save( flags );
+
+ /* generate start condition */
+ i2c_start();
+
+ /* send slave address */
+ if ( EI2CNOACKNLD == i2c_outbyte( theSlave & 0xfe ) )
+ {
+ error = 1;
+ }
+
+ /* now select register */
+ i2c_sda_dir_out();
+
+ if ( EI2CNOACKNLD == i2c_outbyte( theReg ) )
+ {
+ error |= 2;
+ }
+
+ /* repeat start condition */
+ i2c_delay( TLOW );
+ i2c_start();
+
+ /* send slave address */
+ if ( EI2CNOACKNLD == i2c_outbyte( theSlave | 0x01 ) )
+ {
+ error |= 1;
+ }
+
+ /* fetch register */
+ b = i2c_inbyte();
+ /*
+ * last received byte needs to be nacked
+ * instead of acked
+ */
+ i2c_sendnack();
+
+ /* end sequence */
+ i2c_stop();
+
+ /* enable interrupt again */
+ local_irq_restore( flags );
+
+ } while ( error && cntr-- );
+
+ spin_unlock( &i2c_lock );
+
+ return ( b );
+} /* i2c_readreg */
+
+
+/*#---------------------------------------------------------------------------
+ *#
+ *# FUNCTION NAME: i2c_read
+ *#
+ *# DESCRIPTION :
+ *#
+ *# PARAMETERS :
+ *#
+ *# RETURN :
+ *#
+ *#---------------------------------------------------------------------------
+ */
+int i2c_read( unsigned char slave, unsigned char* rbuf, unsigned char rlen )
+{
+ return ( i2c_command( slave, NULL, 0, rbuf, rlen ) );
+} /* i2c_read */
+
+
+/*#---------------------------------------------------------------------------
+ *#
+ *# FUNCTION NAME: i2c_write
+ *#
+ *# DESCRIPTION :
+ *#
+ *# PARAMETERS :
+ *#
+ *# RETURN :
+ *#
+ *#---------------------------------------------------------------------------
+ */
+int i2c_write( unsigned char slave, unsigned char* wbuf, unsigned char wlen )
+{
+ return ( i2c_command( slave, wbuf, wlen, NULL, 0 ) );
+} /* i2c_write */
+
+
+/*#---------------------------------------------------------------------------
+ *#
+ *# FUNCTION NAME: i2c_writeread
+ *#
+ *# DESCRIPTION :
+ *#
+ *# PARAMETERS :
+ *#
+ *# RETURN :
+ *#
+ *#---------------------------------------------------------------------------
+ */
+int i2c_writeread( unsigned char slave
+ , unsigned char* wbuf
+ , unsigned char wlen
+ , unsigned char* rbuf
+ , unsigned char rlen
+ )
+{
+ return ( i2c_command( slave, wbuf, wlen, rbuf, rlen ) );
+} /* i2c_writeread */
+
+
+/*#---------------------------------------------------------------------------
+ *#
+ *# FUNCTION NAME: module_init
+ *#
+ *# DESCRIPTION : this makes sure that i2c_register is called during boot
+ *#
+ *# PARAMETERS :
+ *#
+ *#---------------------------------------------------------------------------
+ */
+module_init( i2c_register );
+
+/****************** END OF FILE i2c.c ********************************/