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

📄 i2c-algo-gm.c

📁 基于GM8180,NSF2200F的I2C驱动,LINUX平台
💻 C
📖 第 1 页 / 共 2 页
字号:
	//printk("aa=%x,flags=%x,len=%x,count=%x\n",msgs->addr,msgs->flags,msgs->len,fara_info->client_count);	ret = GM_i2c_xfer(msgs, 1, fara_info->client_count);	return ret;}EXPORT_SYMBOL_GPL(iic_xfer);#endif/* Implements device specific ioctls.  Higher level ioctls can * be found in i2c-core.c and are typical of any i2c controller (specifying * slave address, timeouts, etc).  These ioctls take advantage of any hardware * features built into the controller for which this algorithm-adapter set * was written.  These ioctls allow you to take control of the data and clock * lines and set the either high or low, * similar to a GPIO pin. */static int algo_control(struct i2c_adapter *adapter, 	unsigned int cmd, unsigned long arg){  struct i2c_algo_iic_data *adap = adapter->algo_data;  struct i2c_iic_msg s_msg;  char *buf;	int ret;		//Add By Ken.Hsieh for debug ioctl	  	printk("algo_control in i2c-algo-GM...\n");  //if (cmd == I2C_SREAD) {  if (cmd == (adapter->id+1)) {	  	if(copy_from_user(&s_msg, (struct i2c_iic_msg *)arg, 				sizeof(struct i2c_iic_msg))) 			return -EFAULT;		buf = kmalloc(s_msg.len, GFP_KERNEL);		if (buf== NULL)			return -ENOMEM;		/* Flush FIFO */		//iic_outw(adap, ITE_I2CFCR, ITE_I2CFCR_FLUSH);		/* Load address */		/*		iic_outw(adap, ITE_I2CSAR,s_msg.addr<<1);		iic_outw(adap, ITE_I2CSSAR,s_msg.waddr & 0xff);		*/		ret = i2c_readbytes(adapter, buf, s_msg.len, 1);		if (ret>=0) {			if(copy_to_user( s_msg.buf, buf, s_msg.len) ) 				ret = -EFAULT;		}		kfree(buf);	}	return 0;}static u32 iic_func(struct i2c_adapter *adap){	return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR | 	       I2C_FUNC_PROTOCOL_MANGLING; }/* -----exported algorithm data: -------------------------------------	*/static struct i2c_algorithm iic_algo = {	.master_xfer	= iic_xfer,	.algo_control	= algo_control, /* ioctl */	.functionality	= iic_func,	};/*  * registering functions to load algorithms at runtime  */int i2c_iic_add_bus(struct i2c_adapter *adap){	struct i2c_algo_iic_data *iic_adap = adap->algo_data;    	struct GMi2c_info *fara_info;    	fara_info=adap;    		if (iic_test) {		int ret = test_bus(iic_adap, adap->name);		if (ret<0)			return -ENODEV;	}	//DEB2(printk("i2c-algo-GM: hw routines for %s registered.\n",	printk("i2c-algo-GM: hw routines for %s registered.\n",	            adap->name);	/* register new adapter to i2c module... */	adap->algo = &iic_algo;	adap->timeout = 100;	/* default values, should	*/	adap->retries = 3;		/* be replaced by defines	*/	fara_info->flags = 0;	return (i2c_add_adapter(adap));	//return 0;}int i2c_iic_del_bus(struct i2c_adapter *adap){	int res;	if ((res = i2c_del_adapter(adap)) < 0)		return res;	DEB2(printk("i2c-algo-GM: adapter unregistered: %s\n",adap->name));	return 0;}int i2c_algo_iic_init (void){    //Init I2C     //*(volatile unsigned int *)(I2C_ADDR) &= ~0x7f00;    *(volatile unsigned int *)(I2C_ADDR+0x14)=1;    *(volatile unsigned int *)(I2C_ADDR+0x8)=0x3e;    //0x40    printk(KERN_INFO "GM i2c algorithm module version(%s) enable successfully!\n",I2C_ALGO_GM_VERSION);    return 0;}EXPORT_SYMBOL(i2c_algo_iic_init);void i2c_algo_iic_exit(void){	return;}EXPORT_SYMBOL(i2c_iic_add_bus);EXPORT_SYMBOL(i2c_iic_del_bus);//francis add for multi-formatenum GM_i2c_state {	STATE_IDLE,	STATE_START,	STATE_READ,	STATE_WRITE,	STATE_STOP};struct GM_i2c {    struct i2c_msg *msg;    unsigned int   msg_num;    unsigned int   msg_idx;    unsigned int   msg_ptr;    enum GM_i2c_state	state;};DECLARE_WAIT_QUEUE_HEAD(i2c_queue);void i2c_handler(void){	wake_up_interruptible(&i2c_queue);}static int CheckStatus(unsigned long wait_status, unsigned int time_out){	#if 1	unsigned long status;	    for (; time_out>0; --time_out)	{		status = I2C_ReadStatus();		//printk("s = %x\n",status);		if ( status & wait_status ){		    break;		}		//if(time_out<500)     }	//printk("time_out = %d\n",time_out);    return (time_out>0);	#endif	#if 0	if(interruptible_sleep_on_timeout(&i2c_queue,msecs_to_jiffies(500)))	{		return 1;	}	return 0;	#endif	#if 0	unsigned int *status;	status = (volatile unsigned int *)(I2C_ADDR+0x4);	if(wait_event_interruptible_timeout(i2c_queue, 				(*status & wait_status) > 0,				msecs_to_jiffies(50)) <= 0)	{		printk("DAT = %x\n",*(volatile unsigned int *)(I2C_ADDR+0x4)&wait_status);		if((*(volatile unsigned int *)(I2C_ADDR+0x4)&wait_status))		return 0;	}	return 0;	#endif}static void GM_i2c_message_start(struct GM_i2c *i2c, struct i2c_msg *msg){    unsigned int addr = (msg->addr & 0x7f) << 1;    unsigned int control;    control =  (I2C_ENABLE | I2C_START | I2C_TBEN | 0x300);    if (msg->flags & I2C_M_RD) {	addr |= 1;    }    if (msg->flags & I2C_M_REV_DIR_ADDR)	addr ^= 1;    I2C_WriteData(addr);    //printk("*%x \n",addr);    I2C_IOCtrl(control);}static inline void GM_i2c_wr(unsigned char bstop){    unsigned int control = 0;//*((volatile unsigned int *)(I2C_ADDR));    if(bstop) {	control &= ~ I2C_START;	control |= I2C_STOP;    }    else	control &= ~ (I2C_START|I2C_STOP);    control |= (I2C_ENABLE|I2C_TBEN);    I2C_IOCtrl(control);}static inline unsigned char GM_i2c_rd(unsigned char bstop){    //unsigned int control = 0;//*(volatile unsigned int *)(I2C_ADDR);    unsigned int control = *(volatile unsigned int *)(I2C_ADDR);    if(bstop) {	control &= ~ I2C_START;	control |= (I2C_STOP|I2C_ACKNAK);    }    else {	control &= ~ (I2C_START|I2C_STOP);    }    control |= (I2C_ENABLE|I2C_TBEN);    I2C_IOCtrl(control);}static inline void GM_i2c_master_complete(struct GM_i2c *i2c, int ret){    i2c->msg_ptr = 0;    i2c->msg = NULL;    i2c->msg_idx ++;    i2c->msg_num = 0;    if (ret)	i2c->msg_idx = ret;}static inline void GM_i2c_stop(struct GM_i2c *i2c, int ret){    /* stop the transfer */    I2C_IOCtrl(I2C_STOP);	// jylee add (20080506)	if(ret != 0){		I2C_IOCtrl(I2C_I2CRST);	}		// jylee add end    i2c->state = STATE_IDLE;    //printk("\n");    GM_i2c_master_complete(i2c, ret);}/* helper functions to determine the current state in the set of * messages we are sending *//* is_lastmsg() * * returns TRUE if the current message is the last in the set */static inline int is_lastmsg(struct GM_i2c *i2c){	return i2c->msg_idx >= (i2c->msg_num - 1);}/* is_msglast * * returns TRUE if we this is the last byte in the current message*/static inline int is_msglast(struct GM_i2c *i2c){	return i2c->msg_ptr == i2c->msg->len-1;}/* is_msgend * * returns TRUE if we reached the end of the current message*/static inline int is_msgend(struct GM_i2c *i2c){	return i2c->msg_ptr >= i2c->msg->len;}static int GM_i2s_nextbyte(struct GM_i2c *i2c, unsigned int iicstat){    unsigned long tmp;    unsigned char byte;    int ret = 0;    switch (i2c->state) {    case STATE_IDLE:	goto out;	break;    case STATE_STOP:	GM_i2c_stop(i2c, 0);	i2c->state = STATE_IDLE;	goto out_ack;    case STATE_START:	/* last thing we did was send a start condition on the	 * bus, or started a new i2c message	 */			if ((iicstat&I2C_NACK) &&	    !(i2c->msg->flags & I2C_M_IGNORE_NAK)) {	    /* ack was not received... */	    printk("I2C:ACK was not received\n");	    GM_i2c_stop(i2c, -EREMOTEIO);	    goto out_ack;	}	if (i2c->msg->flags & I2C_M_RD)	    i2c->state = STATE_READ;	else	    i2c->state = STATE_WRITE;	/* terminate the transfer if there is nothing to do	 * (used by the i2c probe to find devices */	if (is_lastmsg(i2c) && i2c->msg->len == 0) {	    printk("I2C:No Data\n");	    GM_i2c_stop(i2c, 0);	    goto out_ack;	}	if (i2c->state == STATE_READ)	    goto prepare_read;	/* fall through to the write state, as we will need to 	 * send a byte as well */	goto retry_write;    case STATE_WRITE:	if ((iicstat&I2C_NACK) &&	    !(i2c->msg->flags & I2C_M_IGNORE_NAK)) {	    printk("I2C(WRITE): No Ack\n");	    GM_i2c_stop(i2c, -ECONNREFUSED);	    goto out_ack;	}	/* we are writing data to the device... check for the	 * end of the message, and if so, work out what to do	 */    retry_write:	if (!(is_msglast(i2c) || is_msgend(i2c))) {	    byte = i2c->msg->buf[i2c->msg_ptr++];	    I2C_WriteData(byte);	    //printk("*%x ",byte);	    GM_i2c_wr(0);	} else {	    if (!is_lastmsg(i2c)) {		if(is_msglast(i2c)) {		    byte = i2c->msg->buf[i2c->msg_ptr++];		    I2C_WriteData(byte);		    //printk("*%x ",byte);		    if((i2c->msg+1)->flags & I2C_M_NOSTART){			GM_i2c_wr(0);		    }		    else {			GM_i2c_wr(1);		    }		}		else {		    /* we need to go to the next i2c message */		    i2c->msg_ptr = 0;		    i2c->msg_idx ++;		    i2c->msg++;		    /* check to see if we need to do another message */		    if (i2c->msg->flags & I2C_M_NOSTART) {		    	if (i2c->msg->flags & I2C_M_RD) {		    	    GM_i2c_stop(i2c, -EINVAL);		    	    goto out;		    	}		    	goto retry_write;		    } else {			/* send the new start */						GM_i2c_message_start(i2c, i2c->msg);			i2c->state = STATE_START;			break;		    }		}	    } 	    else {		byte = i2c->msg->buf[i2c->msg_ptr++];		I2C_WriteData(byte);		//printk("*%x ",byte);		GM_i2c_wr(1);		i2c->state = STATE_STOP;	    }	}	break;    case STATE_READ:	/* we have a byte of data in the data register, do 	 * something with it, and then work out wether we are	 * going to do any more read/write	 */		if (!(i2c->msg->flags & I2C_M_IGNORE_NAK) &&	    !(is_msglast(i2c))) {	    if ((iicstat&I2C_NACK)) {		printk("I2C(READ): No Ack\n");		GM_i2c_stop(i2c, -ECONNREFUSED);		goto out_ack;	    }	}	byte = I2C_ReadData();	i2c->msg->buf[i2c->msg_ptr++] = byte;	    prepare_read:	if (!is_msgend(i2c)){	    /* last byte of buffer */	    if (is_msglast(i2c)){		GM_i2c_rd(1);	    }	    else {		GM_i2c_rd(0);	    }	} 	else{	    /* ok, we've read the entire buffer, see if there	     * is anything else we need to do */	    if (is_lastmsg(i2c)) {		/* last message, send stop and complete */		GM_i2c_stop(i2c, 0);		i2c->state = STATE_IDLE;	    } else {		/* go to the next transfer */		i2c->msg_ptr = 0;		i2c->msg_idx++;		i2c->msg++;		if (i2c->msg->flags & I2C_M_RD) {		    goto prepare_read;		}		else {		    if (i2c->msg->flags & I2C_M_NOSTART) {			GM_i2c_stop(i2c, -EINVAL);			goto out;		    }		    GM_i2c_message_start(i2c, i2c->msg);		    i2c->state = STATE_START;		}	    }	}	break;    }     out_ack: out:    return ret;}extern unsigned int status;int GM_i2c_doxfer(struct i2c_msg *msgs, int num){    struct GM_i2c i2c;    int ret = 0;    i2c.msg     = msgs;    i2c.msg_num = num;    i2c.msg_ptr = 0;    i2c.msg_idx = 0;    i2c.state   = STATE_START;     GM_i2c_message_start(&i2c, i2c.msg);    while(i2c.state != STATE_IDLE) {	ret = CheckStatus(I2C_DT|I2C_DR, 1000);	#if 1	if(!ret) {	    unsigned int addr = (i2c.msg->addr & 0x7f) << 1;	    int i;	    if (i2c.msg->flags & I2C_M_RD)			addr |= 1;		#if 1	    printk("I2C:(%#x", addr);	    for(i = 0; i < i2c.msg->len; i++) {			printk(" %#x", i2c.msg->buf[i]);	    }	    printk(")Timeout!\n");		#endif	    GM_i2c_stop(&i2c, -EAGAIN);	    goto out;	}	#endif	status = I2C_ReadStatus();	GM_i2s_nextbyte(&i2c, status);    } out:    ret = i2c.msg_idx;    return ret;}//---------------------------------------------------------------/* The MODULE_* macros resolve to nothing if MODULES is not defined * when this file is compiled. */MODULE_AUTHOR("GM Video Software<www.grain-media.com>");MODULE_DESCRIPTION("GM iic algorithm");MODULE_LICENSE("GM License");//Marked By Ken.Hsieh//MODULE_PARM(iic_test, "i");//MODULE_PARM(iic_scan, "i");//MODULE_PARM(i2c_debug,"i");/*MODULE_PARM_DESC(iic_test, "Test if the I2C bus is available");MODULE_PARM_DESC(iic_scan, "Scan for active chips on the bus");MODULE_PARM_DESC(i2c_debug,        "debug level - 0 off; 1 normal; 2,3 more verbose; 9 iic-protocol");*//* This function resolves to init_module (the function invoked when a module * is loaded via insmod) when this file is compiled with MODULES defined. * Otherwise (i.e. if you want this driver statically linked to the kernel), * a pointer to this function is stored in a table and called * during the intialization of the kernel (in do_basic_setup in /init/main.c)  * * All this functionality is complements of the macros defined in linux/init.h *///module_init(i2c_algo_iic_init);/* If MODULES is defined when this file is compiled, then this function will * resolved to cleanup_module. *///module_exit(i2c_algo_iic_exit);

⌨️ 快捷键说明

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