📄 i2c-algo-ip3203.c
字号:
/* -------------------------------------------------------------------------- *//* i2c-algo-IP3203.c i2c driver algorithms for PNX8550 High Performance ports *//* -------------------------------------------------------------------------- *//* This module is the work of Willem van Beek, * evidently inspired by Simon G. Vogl. * * Restriction : * Slave Transmitter functionality not working (yet) * Slave Receiver doesn't use DMA functionality * No time-out (or watchdog) on Slave functionality * * *//*-------------------------------------------------------------------------------Standard include files:-------------------------------------------------------------------------------*/#include <linux/kernel.h>#include <linux/module.h>#include <linux/delay.h>#include <linux/slab.h>#include <linux/version.h>#include <linux/init.h>#include <linux/ioport.h>#include <linux/errno.h>#include <linux/sched.h>#include <linux/interrupt.h>#include <linux/string.h>#include <linux/fs.h>#include <linux/mm.h>/*-------------------------------------------------------------------------------Project include files:-------------------------------------------------------------------------------*/#include <linux/i2c.h>#include "i2c-algo-IP3203.h"#include <asm/irq.h>#include <asm/uaccess.h>#include <asm/philips/pnx8550/pnx8550_int.h>#include <asm/io.h>#ifndef FALSE#define FALSE 0#define TRUE 1#endif#define errids_Ok 0#define errids_IsI2cHardwareError 0x01#define errids_IsI2cDeviceError 0x02#define errids_IsI2cWriteError 0x03#define evMasterReady 0x0001#define evSlaveRxIntermediateNtf 0x0002#define evSlaveReceiverReady 0x0004#define evSlaveReadRequest 0x0008#define evSlaveTransmitterReady 0x0010#define evSlaveStopCondition 0x0020#ifndef BOOL#define BOOL int#endif/* --- adapters */#define NR_I2C_DEVICES 2 /* Two High Performance controllers : Don't change this value */#define I2C_HIGH_PERFORMANCE_PORT_1 0x00 /* IP3203 Controller on the Viper */#define I2C_HIGH_PERFORMANCE_PORT_2 0x01 /* IP3203 Controller on the Viper */#define IP3203_UNIT0 0xBBE45000#define IP3203_UNIT1 0xBBE46000#define MODULE_CLOCK 27000 /* I2C module clock speed in KHz */#define I2CADDRESS( address ) ((address) & 0x00FE) /* only 7 bits I2C address implemented */#define TIMER_OFF 0//#define USE_DMAtypedef enum{ Idle = 0x00, MasterTransmitter = 0x01, MasterReceiver = 0x02, SlaveReceiver = 0x04, SlaveTransmitter = 0x08,} I2cMode;struct I2cBusObject{ unsigned char * mst_txbuf; /* Master mode variables */ int mst_txbuflen; int mst_txbufindex; unsigned char * mst_rxbuf; int mst_rxbuflen; int mst_rxbufindex; int mst_address; wait_queue_head_t iic_wait_master; unsigned long int_pin; unsigned int mst_status;// int mst_timer;// int mst_timeout;// BOOL mst_timeout_valid; unsigned char * slv_buf; /* Slave mode variables */ int slv_bufsize; int slv_buflen; int slv_bufindex; BOOL slv_enabled;// int slv_timer;// int slv_timeout;// BOOL slv_timeout_valid; int offset; /* I2C HW controller address offset, required by HAL */ I2cMode mode; int isr_event;// BOOL bus_blocked;#ifdef USE_DMA unsigned char * dma_bufptr; unsigned char * dma_clientbuf; int dma_len; I2cMode dma_transmit;#endif struct fasync_struct ** slv_usr_notify;};/* Local Macros for IP3203 */static __inline void STAOUT(struct I2cBusObject * a, int p){ int val = read_IP3203_I2CCON(a); if (p) { val |= IP3203_STA; } else { val &= ~IP3203_STA; } write_IP3203_I2CCON(a, val);}static __inline void STOOUT(struct I2cBusObject * a, int p){ int val = read_IP3203_I2CCON(a); if (p) { val |= IP3203_SETSTO; } else { val &= ~IP3203_SETSTO; } write_IP3203_I2CCON(a, val);}static __inline void AAOUT(struct I2cBusObject * a, int p){ int val = read_IP3203_I2CCON(a); if (p) { val |= IP3203_AA; } else { val &= ~IP3203_AA; } write_IP3203_I2CCON(a, val);}static __inline void ENABLE_I2C_CONTROLLER(struct I2cBusObject * a){ int val = read_IP3203_I2CCON(a); val |= IP3203_EN; write_IP3203_I2CCON(a, val);}static __inline void DISABLE_I2C_CONTROLLER(struct I2cBusObject * a){ int val = read_IP3203_I2CCON(a); val &= ~IP3203_EN; write_IP3203_I2CCON(a, val);}static __inline void CLEAR_I2C_INTERRUPT(struct I2cBusObject * a){ write_IP3203_INT_CLEAR(a, 1);}static __inline void ENABLE_I2C_INTERRUPT(struct I2cBusObject * a){ write_IP3203_INT_ENABLE(a, IP3203_INTBIT);}static __inline void DISABLE_I2C_INTERRUPT(struct I2cBusObject * a){ write_IP3203_INT_ENABLE(a, 0);}/* ----- global defines ----------------------------------------------- */#define DEB(x) if (i2c_debug>=1) x#define DEB2(x) if (i2c_debug>=2) x#define DEB3(x) if (i2c_debug>=3) x /* print several statistical values*/#define ASSERT(x) if (!(x)) dev_dbg(&i2c_adap->dev, "ASSERTION FAILED at line %d in file %s\n", __LINE__, __FILE__);/* Types and defines: */#define TIMEOUT 200 /* Should be wait period of >100us i.e 1 byte @100KHz *//* Local Types */static unsigned long IP3203_controller[NR_I2C_DEVICES] = { IP3203_UNIT0, IP3203_UNIT1 };static unsigned long IP3203_intpin[NR_I2C_DEVICES] = { PNX8550_INT_I2C1, PNX8550_INT_I2C2 };static struct i2c_adapter * slave_device = NULL;static void do_slave_tasklet(unsigned long);DECLARE_TASKLET(IP3203_slave_tasklet, do_slave_tasklet, 0);#ifdef USE_DMAstatic void dma_start( unsigned char *clientbuf, struct i2c_adapter * i2c_adap, int len, I2cMode transmitmode );static void dma_end( struct i2c_adapter * i2c_adap );static void __inline local_memcpy( void *dest, void *src, int len );static void __inline local_memcpy_receive( void *dest, void *src, int len ); /* Temp, find a better solution */#endif#define div_DmaBufSize 128static struct I2cBusObject IP3203_i2cbus[NR_I2C_DEVICES];static int i2c_debug = 0;/* This function is called from Primary ISR */static void recover_from_hardware_error(struct i2c_adapter * i2c_adap){ struct I2cBusObject * busptr = (struct I2cBusObject *)i2c_adap->algo_data; dev_dbg(&i2c_adap->dev, "Recover from HW Error\n"); DISABLE_I2C_CONTROLLER( busptr ); STAOUT( busptr, 0 ); /* Don't generate START condition */ STOOUT( busptr, 1 ); /* Recover from error condition */ if( ( busptr->mode == MasterReceiver ) || ( busptr->mode == MasterTransmitter ) ) { busptr->mst_status = errids_IsI2cHardwareError; busptr->isr_event |= evMasterReady; wake_up_interruptible(&(busptr->iic_wait_master)); } if ( busptr->slv_enabled ) { AAOUT( busptr, 1 ); /* ACK bit will be returned after slave address reception */ } else { AAOUT( busptr, 0 ); /* NOT ACK bit will be returned after slave address reception */ } busptr->mode = Idle; CLEAR_I2C_INTERRUPT( busptr ); /* Reset interrupt */ ENABLE_I2C_CONTROLLER( busptr ); /* Enable I2C controller */}static __inline void iic_interrupt_idle(struct i2c_adapter * i2c_adap, struct I2cBusObject * busptr, int i2c_state){ switch (i2c_state) { case 0x08: /* Master Transmitter or Master Receiver: A START condition has been transmitted */ if( ( busptr->mst_txbufindex < busptr->mst_txbuflen ) || ( busptr->mst_rxbufindex == busptr->mst_rxbuflen ) ) /* if bytes to transmit or no bytes to receive ? */ { int myaddr = (busptr->mst_address & 0xFE); dev_dbg(&i2c_adap->dev, "START TRANSMITTED, Read bit cleared addr = %x\n", myaddr); write_IP3203_I2CDAT(busptr, myaddr); /* Read bit cleared */ busptr->mode = MasterTransmitter;#ifdef USE_DMA { int dmalen; if( busptr->mst_txbuflen <= div_DmaBufSize ) { dmalen = busptr->mst_txbuflen; } else { dmalen = div_DmaBufSize; } dma_start( busptr->mst_txbuf, i2c_adap, dmalen, MasterTransmitter); busptr->mst_txbufindex = dmalen; }#endif } else { int myaddr = ((busptr->mst_address & 0xFE) | 0x01); dev_dbg(&i2c_adap->dev, "START TRANSMITTED, Read bit set(%x)\n", myaddr); write_IP3203_I2CDAT(busptr, myaddr); /* Read bit set */ busptr->mode = MasterReceiver; } STAOUT( busptr, 0 );/* Clear STA flag */ CLEAR_I2C_INTERRUPT( busptr ); /* Reset interrupt */ break; case 0x60: /* Own SLA+W has been received; ACK has been returned */ busptr->slv_bufindex = 1; /* reset buffer pointer !!! */ AAOUT( busptr, busptr->slv_enabled ); /* ACK bit will be returned after next byte reception */ busptr->mode = SlaveReceiver;// Todo : Start timeout timer in tasklet// tasklet_schedule(&IP3203_slave_tasklet); CLEAR_I2C_INTERRUPT(busptr); /* Don't reset i2c interrupt */ break; case 0xA8: /* Own SLA+R has been received; ACK has been returned */ busptr->mode = SlaveTransmitter; busptr->isr_event |= evSlaveReadRequest; slave_device = i2c_adap; tasklet_schedule(&IP3203_slave_tasklet); /* Don't reset i2c interrupt */ break; case 0x70: /* General call address (0x00) has been received; ACK has been returned */ /* fall through; */ case 0x78: /* Arbitration lost in SLA+R/~W as master; General call address (0x00) has been received; ACK has been returned */ /* fall through; */ default: recover_from_hardware_error( i2c_adap ); break; }}static __inline void iic_interrupt_master_transmitter(struct i2c_adapter * i2c_adap, struct I2cBusObject * busptr, int i2c_state){ switch (i2c_state) { case 0x10: /* Master Transmitter or Master Receiver: A repeated START condition has been transmitted */ /* Note : A repeated START should not occur when in MasterReceiver mode in this implementation */ if( ( busptr->mst_txbufindex < busptr->mst_txbuflen ) || ( busptr->mst_rxbufindex == busptr->mst_rxbuflen ) ) /* if bytes to transmit or no bytes to receive ? */ { int myaddr = (busptr->mst_address & 0xFE);dev_dbg(&i2c_adap->dev, "START TRANSMITTED, Read bit cleared addr = %x\n", myaddr); write_IP3203_I2CDAT(busptr, myaddr); /* Read bit cleared */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -