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

📄 i2c-algo-8xx.c

📁 I2C总线LINUX驱动程序
💻 C
📖 第 1 页 / 共 2 页
字号:
		return -EREMOTEIO;	}	if (rbdf->cbd_sc & BD_SC_EMPTY) {		/* force_close(cpm); */		if (cpm_debug){			printk("IIC read; complete but rbuf empty\n");			printk("tx sc %04x, rx sc %04x\n",			       tbdf->cbd_sc, rbdf->cbd_sc);		}		return -EREMOTEIO;	}	if (rbdf->cbd_sc & BD_SC_OV) {		if (cpm_debug)			printk("IIC read; Overrun\n");		return -EREMOTEIO;;	}	if (cpm_debug) printk("read %d bytes\n", rbdf->cbd_datlen);	if (rbdf->cbd_datlen < count) {		if (cpm_debug)			printk("IIC read; short, wanted %d got %d\n",			       count, rbdf->cbd_datlen);		return 0;	}	return count;}/* Write to IIC... * addr = address byte, with r/w flag already set */static intcpm_iic_write(struct i2c_algo_8xx_data *cpm, u_char abyte, char *buf,int count){	volatile iic_t *iip = cpm->iip;	volatile i2c8xx_t *i2c = cpm->i2c;	volatile cpm8xx_t *cp = cpm->cp;	volatile cbd_t	*tbdf;	u_char *tb;	unsigned long flags, tmo;	/* check for and use a microcode relocation patch */	if (cpm->reloc) {		cpm_reset_iic_params(iip);	}	tb = cpm->temp;	tb = (u_char *)(((uint)tb + 15) & ~15);	*tb = abyte;		/* Device address byte w/rw flag */	flush_dcache_range((unsigned long) tb, (unsigned long) (tb+1));	flush_dcache_range((unsigned long) buf, (unsigned long) (buf+count));	if (cpm_debug) printk("cpm_iic_write(abyte=0x%x)\n", abyte);	/* set up 2 descriptors */	tbdf = (cbd_t *)&cp->cp_dpmem[iip->iic_tbase];	tbdf[0].cbd_bufaddr = __pa(tb);	tbdf[0].cbd_datlen = 1;	tbdf[0].cbd_sc = BD_SC_READY | BD_IIC_START;	tbdf[1].cbd_bufaddr = __pa(buf);	tbdf[1].cbd_datlen = count;	tbdf[1].cbd_sc = BD_SC_READY | BD_SC_INTRPT | BD_SC_LAST | BD_SC_WRAP;	if(count > 16){		/* Chip bug, set enable here */		local_irq_save(flags);		i2c->i2c_i2cmr = 0x13;	/* Enable some interupts */		i2c->i2c_i2cer = 0xff;		i2c->i2c_i2mod |= 1;	/* Enable */		i2c->i2c_i2com |= 0x80;	/* Begin transmission */				/* Wait for IIC transfer */		tmo = interruptible_sleep_on_timeout(&iic_wait,1*HZ);		local_irq_restore(flags);	} else {  /* busy wait for small transfers, its faster */		i2c->i2c_i2cmr = 0x00;	/* Disable I2C interupts */		i2c->i2c_i2cer = 0xff;		i2c->i2c_i2mod |= 1;	/* Enable */		i2c->i2c_i2com |= 0x80;	/* Begin transmission */		tmo = jiffies + 1*HZ; 		while(!(i2c->i2c_i2cer & 0x12 || time_after(jiffies, tmo))); /* Busy wait, with a timeout */	}			if (signal_pending(current) || !tmo){		force_close(cpm);		if(cpm_debug && !tmo) 			printk("IIC write: timeout!\n");		return -EIO;	}	#if I2C_CHIP_ERRATA	/* Chip errata, clear enable. This is not needed on rev D4 CPUs.	 Disabling I2C too early may cause too short stop condition */	udelay(4);	i2c->i2c_i2mod &= ~1;#endif	if (cpm_debug) {		printk("tx0 sc %04x, tx1 sc %04x\n",		       tbdf[0].cbd_sc, tbdf[1].cbd_sc);	}	if (tbdf->cbd_sc & BD_SC_NAK) {		if (cpm_debug) 			printk("IIC write; no ack\n");		return 0;	}	  	if (tbdf->cbd_sc & BD_SC_READY) {		if (cpm_debug)			printk("IIC write; complete but tbuf ready\n");		return 0;	}	return count;}/* See if an IIC address exists.. * addr = 7 bit address, unshifted */static intcpm_iic_tryaddress(struct i2c_algo_8xx_data *cpm, int addr){	volatile iic_t *iip = cpm->iip;	volatile i2c8xx_t *i2c = cpm->i2c;	volatile cpm8xx_t *cp = cpm->cp;	volatile cbd_t *tbdf, *rbdf;	u_char *tb;	unsigned long flags, len, tmo;	if (cpm_debug > 1)		printk("cpm_iic_tryaddress(cpm=%p,addr=%d)\n", cpm, addr);	/* check for and use a microcode relocation patch */	if (cpm->reloc) {		cpm_reset_iic_params(iip);	}	if (cpm_debug && addr == 0) {		printk("iip %p, dp_addr 0x%x\n", cpm->iip, cpm->dp_addr);		printk("iic_tbase %d, r_tbase %d\n", iip->iic_tbase, r_tbase);	}	tbdf = (cbd_t *)&cp->cp_dpmem[iip->iic_tbase];	rbdf = (cbd_t *)&cp->cp_dpmem[iip->iic_rbase];	tb = cpm->temp;	tb = (u_char *)(((uint)tb + 15) & ~15);	/* do a simple read */	tb[0] = (addr << 1) | 1;	/* device address (+ read) */	len = 2;	flush_dcache_range((unsigned long) tb, (unsigned long) (tb+2));	tbdf->cbd_bufaddr = __pa(tb);	tbdf->cbd_datlen = len;	tbdf->cbd_sc =		BD_SC_READY | BD_SC_LAST |		BD_SC_WRAP | BD_IIC_START;	rbdf->cbd_datlen = 0;	rbdf->cbd_bufaddr = __pa(tb+2);	rbdf->cbd_sc = BD_SC_EMPTY | BD_SC_WRAP | BD_SC_INTRPT;	local_irq_save(flags);	i2c->i2c_i2cmr = 0x13;	/* Enable some interupts */	i2c->i2c_i2cer = 0xff;	i2c->i2c_i2mod |= 1;	/* Enable */	i2c->i2c_i2com |= 0x80;	/* Begin transmission */	if (cpm_debug > 1) printk("about to sleep\n");	/* wait for IIC transfer */	tmo = interruptible_sleep_on_timeout(&iic_wait,1*HZ);	local_irq_restore(flags);#ifdef I2C_CHIP_ERRATA	/* Chip errata, clear enable. This is not needed on rev D4 CPUs.	 Disabling I2C too early may cause too short stop condition */	udelay(4);	i2c->i2c_i2mod &= ~1;#endif	if (signal_pending(current) || !tmo){		force_close(cpm);		if(cpm_debug && !tmo) 			printk("IIC tryaddress: timeout!\n");		return -EIO;	}	if (cpm_debug > 1) printk("back from sleep\n");	if (tbdf->cbd_sc & BD_SC_NAK) {		if (cpm_debug > 1) printk("IIC try; no ack\n");		return 0;	}	  	if (tbdf->cbd_sc & BD_SC_READY) {		printk("IIC try; complete but tbuf ready\n");	}		return 1;}static int cpm_xfer(struct i2c_adapter *adap,		    struct i2c_msg msgs[], 		    int num){	struct i2c_algo_8xx_data *cpm = adap->algo_data;	struct i2c_msg *pmsg;	int i, ret;	u_char addr;    	for (i = 0; i < num; i++) {		pmsg = &msgs[i];		if (cpm_debug)			printk("i2c-algo-8xx.o: "			       "#%d addr=0x%x flags=0x%x len=%d\n buf=%lx\n",			       i, pmsg->addr, pmsg->flags, pmsg->len, (unsigned long)pmsg->buf);		addr = pmsg->addr << 1;		if (pmsg->flags & I2C_M_RD )			addr |= 1;		if (pmsg->flags & I2C_M_REV_DIR_ADDR )			addr ^= 1;    		if (!(pmsg->flags & I2C_M_NOSTART)) {		}		if (pmsg->flags & I2C_M_RD ) {			/* read bytes into buffer*/			ret = cpm_iic_read(cpm, addr, pmsg->buf, pmsg->len);			if (cpm_debug)				printk("i2c-algo-8xx.o: read %d bytes\n", ret);			if (ret < pmsg->len ) {				return (ret<0)? ret : -EREMOTEIO;			}		} else {			/* write bytes from buffer */			ret = cpm_iic_write(cpm, addr, pmsg->buf, pmsg->len);			if (cpm_debug)				printk("i2c-algo-8xx.o: wrote %d\n", ret);			if (ret < pmsg->len ) {				return (ret<0) ? ret : -EREMOTEIO;			}		}	}	return (num);}static u32 cpm_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 cpm_algo = {	.name		= "MPC8xx CPM algorithm",	.id		= I2C_ALGO_MPC8XX,	.master_xfer	= cpm_xfer,	.functionality	= cpm_func,};/*  * registering functions to load algorithms at runtime  */int i2c_8xx_add_bus(struct i2c_adapter *adap){	int i;	struct i2c_algo_8xx_data *cpm = adap->algo_data;	if (cpm_debug)		printk("i2c-algo-8xx.o: hw routines for %s registered.\n",		       adap->name);	/* register new adapter to i2c module... */	adap->id |= cpm_algo.id;	adap->algo = &cpm_algo;	i2c_add_adapter(adap);	cpm_iic_init(cpm);}int i2c_8xx_del_bus(struct i2c_adapter *adap){	struct i2c_algo_8xx_data *cpm = adap->algo_data;	cpm_iic_shutdown(cpm);	return i2c_del_adapter(adap);}EXPORT_SYMBOL(i2c_8xx_add_bus);EXPORT_SYMBOL(i2c_8xx_del_bus);MODULE_AUTHOR("Brad Parker <brad@heeltoe.com>");MODULE_DESCRIPTION("I2C-Bus MPC8XX algorithm");MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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