⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 i2c-iop3xx.c

📁 I2C总线LINUX驱动程序
💻 C
📖 第 1 页 / 共 2 页
字号:
/* ------------------------------------------------------------------------- *//* i2c-iop3xx.c i2c driver algorithms for Intel XScale IOP3xx                *//* ------------------------------------------------------------------------- *//*   Copyright (C) 2003 Peter Milne, D-TACQ Solutions Ltd *                      <Peter dot Milne at D hyphen TACQ dot com>    This program is free software; you can redistribute it and/or modify    it under the terms of the GNU General Public License as published by    the Free Software Foundation; either version 2 of the License.    This program is distributed in the hope that it will be useful,    but WITHOUT ANY WARRANTY; without even the implied warranty of    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    GNU General Public License for more details.    You should have received a copy of the GNU General Public License    along with this program; if not, write to the Free Software    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.                *//* ------------------------------------------------------------------------- *//*   With acknowledgements to i2c-algo-ibm_ocp.c by    Ian DaSilva, MontaVista Software, Inc. idasilva@mvista.com   And i2c-algo-pcf.c, which was created by Simon G. Vogl and Hans Berglund:     Copyright (C) 1995-1997 Simon G. Vogl, 1998-2000 Hans Berglund      And which acknowledged Ky鰏ti M鋖kki <kmalkki@cc.hut.fi>,   Frodo Looijaard <frodol@dds.nl>, Martin Bailey<mbailey@littlefeet-inc.com>  ---------------------------------------------------------------------------*/#include <linux/interrupt.h>#include <linux/kernel.h>#include <linux/module.h>#include <linux/delay.h>#include <linux/slab.h>#include <linux/init.h>#include <linux/errno.h>#include <linux/sched.h>#include <linux/i2c.h>#include <asm/arch-iop3xx/iop321.h>#include <asm/arch-iop3xx/iop321-irqs.h>#include "i2c-iop3xx.h"/* ----- global defines ----------------------------------------------- */#define PASSERT(x) do { if (!(x) ) \                printk(KERN_CRIT "PASSERT %s in %s:%d\n", #x, __FILE__, __LINE__ );\        } while (0)#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 DEBPROTO(x) if (i2c_debug>=9) x; 	/* debug the protocol by showing transferred bits *//* ----- global variables ---------------------------------------------	*//* module parameters: */static int i2c_debug = 1;static inline unsigned char iic_cook_addr(struct i2c_msg *msg) {	unsigned char addr;	addr = ( msg->addr << 1 );	if (msg->flags & I2C_M_RD )		addr |= 1;/* PGM: what is M_REV_DIR_ADDR - do we need it ?? */	if (msg->flags & I2C_M_REV_DIR_ADDR )		addr ^= 1;	return addr;   }static inline void iop3xx_adap_reset(struct i2c_algo_iop3xx_data *iop3xx_adap){	// Follows devman 9.3	*iop3xx_adap->biu->CR = IOP321_ICR_UNIT_RESET;	*iop3xx_adap->biu->SR = IOP321_ISR_CLEARBITS;	*iop3xx_adap->biu->CR = 0;} static inline void iop3xx_adap_set_slave_addr(	struct i2c_algo_iop3xx_data *iop3xx_adap ){	*iop3xx_adap->biu->SAR = MYSAR;}static inline void iop3xx_adap_enable( 	struct i2c_algo_iop3xx_data *iop3xx_adap ){	u32 cr = IOP321_ICR_GCD|IOP321_ICR_SCLEN|IOP321_ICR_UE;/* NB SR bits not same position as CR IE bits :-( */	iop3xx_adap->biu->SR_enabled = 		IOP321_ISR_ALD|IOP321_ISR_BERRD|		IOP321_ISR_RXFULL|IOP321_ISR_TXEMPTY;	cr |= IOP321_ICR_ALDIE|IOP321_ICR_BERRIE|		IOP321_ICR_RXFULLIE|IOP321_ICR_TXEMPTYIE;	*iop3xx_adap->biu->CR = cr;}static void iop3xx_adap_transaction_cleanup( 	struct i2c_algo_iop3xx_data *iop3xx_adap ){	unsigned cr = *iop3xx_adap->biu->CR;		cr &= ~(IOP321_ICR_MSTART | IOP321_ICR_TBYTE | 		IOP321_ICR_MSTOP | IOP321_ICR_SCLEN );	*iop3xx_adap->biu->CR = cr;}static void iop3xx_adap_final_cleanup( 	struct i2c_algo_iop3xx_data *iop3xx_adap ){	unsigned cr = *iop3xx_adap->biu->CR;		cr &= ~(IOP321_ICR_ALDIE|IOP321_ICR_BERRIE|		IOP321_ICR_RXFULLIE|IOP321_ICR_TXEMPTYIE);	iop3xx_adap->biu->SR_enabled = 0;	*iop3xx_adap->biu->CR = cr;}static void iop3xx_i2c_handler( int this_irq, 				void *dev_id, 				struct pt_regs *regs) /*  * NB: the handler has to clear the source of the interrupt!  * Then it passes the SR flags of interest to BH via adap data */{#define DFN KERN_DEBUG "iop3xx_i2c_handler() "	struct i2c_algo_iop3xx_data *iop3xx_adap = dev_id;	u32 sr = *iop3xx_adap->biu->SR;	DEB2(printk(DFN" SR 0x%08x jiffies %10ld\n", sr, jiffies ));	if ( (sr &= iop3xx_adap->biu->SR_enabled) ){		*iop3xx_adap->biu->SR = sr;		iop3xx_adap->biu->SR_received |= sr;		DEB2(printk(DFN"  wake client for 0x%08x\n", 			    iop3xx_adap->biu->SR_received ));		wake_up_interruptible(&iop3xx_adap->waitq);	}else{		DEB(printk(DFN"Interrupt with no status 0x%08x\n", sr ) );	}#undef DFN}static int iop3xx_adap_error( u32 sr )// check all error conditions, clear them , report most important{	int rc = 0;	if ( (sr&IOP321_ISR_BERRD) ) {		if ( !rc ) rc = -I2C_ERR_BERR;	}	if ( (sr&IOP321_ISR_ALD) ){		if ( !rc ) rc = -I2C_ERR_ALD;			}	return rc;	}static inline u32 get_srstat( struct i2c_algo_iop3xx_data *iop3xx_adap  ){#define DFN KERN_DEBUG "get_srstat() "	unsigned long flags;	u32 sr;	DEB2(printk(DFN" enter lock\n" ));	spin_lock_irqsave( &iop3xx_adap->lock, flags );	sr = iop3xx_adap->biu->SR_received;	iop3xx_adap->biu->SR_received = 0;	spin_unlock_irqrestore( &iop3xx_adap->lock, flags );	DEB2(printk(DFN" leave lock\n" ));	return sr;#undef DFN}/* * sleep until interrupted, then recover and analyse the SR * saved by handler */typedef int (* CompareFunc)( unsigned test, unsigned mask );/* returns 1 on correct comparison */static int iop3xx_adap_wait_event( struct i2c_algo_iop3xx_data *iop3xx_adap, 			    unsigned flags, unsigned* status,			    CompareFunc compare ){#define DFN KERN_DEBUG "adap_wait_event() "	unsigned sr = 0;	int interrupted;	int done;	int rc;	long jiffies1 = jiffies;	do {		interrupted = wait_event_interruptible_timeout (			iop3xx_adap->waitq,			(done = compare( sr = get_srstat(iop3xx_adap),flags )),			iop3xx_adap->timeout			);		if ( (rc = iop3xx_adap_error( sr )) < 0 ){			*status = sr;			return rc;		}else if ( !interrupted ){			*status = sr;			DEB(printk(DFN "TIMEOUT %ld\n", jiffies ));			return rc = -ETIMEDOUT;		}	} while( !done );	*status = sr;	DEB3(printk( DFN"%ld %ld\n", jiffies1, jiffies ) );	return rc = 0;#undef DFN}/* * Concrete CompareFuncs  */static int all_bits_clear( unsigned test, unsigned mask ) {	return (test&mask) == 0;}static int any_bits_set( unsigned test, unsigned mask ) {	return (test&mask) != 0;}static int iop3xx_adap_wait_tx_done(	struct i2c_algo_iop3xx_data *iop3xx_adap, int *status){	return iop3xx_adap_wait_event( 		iop3xx_adap, 	        IOP321_ISR_TXEMPTY|IOP321_ISR_ALD|IOP321_ISR_BERRD,		status, any_bits_set );}static int iop3xx_adap_wait_rx_done(	struct i2c_algo_iop3xx_data *iop3xx_adap, int *status){	return iop3xx_adap_wait_event( 		iop3xx_adap, 		IOP321_ISR_RXFULL|IOP321_ISR_ALD|IOP321_ISR_BERRD,		status,	any_bits_set );}static int iop3xx_adap_wait_idle(	struct i2c_algo_iop3xx_data *iop3xx_adap, int *status){	return iop3xx_adap_wait_event( 		iop3xx_adap, IOP321_ISR_UNITBUSY, status, all_bits_clear );}//// Description: This performs the IOP3xx initialization sequence// Valid for IOP321. Maybe valid for IOP310?.//static int iop3xx_adap_init (struct i2c_algo_iop3xx_data *iop3xx_adap){	*IOP321_GPOD &= ~(iop3xx_adap->channel==0?			  IOP321_GPOD_I2C0:			  IOP321_GPOD_I2C1);	iop3xx_adap_reset( iop3xx_adap );	iop3xx_adap_set_slave_addr( iop3xx_adap );	iop3xx_adap_enable( iop3xx_adap );	        DEB2(printk(KERN_DEBUG "iic_init: Initialized IIC on IOP3xx\n"));        return 0;}static int iop3xx_adap_send_target_slave_addr( 	struct i2c_algo_iop3xx_data *iop3xx_adap, struct i2c_msg* msg ){#define DFN KERN_DEBUG "iop3xx_adap_send_target_slave_addr() "	unsigned cr = *iop3xx_adap->biu->CR;	int status;	int rc;	*iop3xx_adap->biu->DBR = iic_cook_addr( msg );		cr &= ~(IOP321_ICR_MSTOP|IOP321_ICR_NACK);	cr |= IOP321_ICR_MSTART | IOP321_ICR_TBYTE;	*iop3xx_adap->biu->CR = cr;	rc = iop3xx_adap_wait_tx_done( iop3xx_adap, &status );/* this assert fires every time, contrary to IOP manual		PASSERT( (status&IOP321_ISR_UNITBUSY)!=0 );*/	PASSERT( (status&IOP321_ISR_RXREAD)==0 );	     	if ( rc < 0 ){

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -