📄 i2c-algo-gm.c
字号:
//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 + -