i2c-omap24xx.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 631 行 · 第 1/2 页

C
631
字号
			}			if (status & I2C_STAT_AL) {				/* We lost control of the bus to another 				 * bus master.  Try this transfer again.				 */				i2c_reg_out(oadap, I2C_STAT, I2C_STAT_AL);				i2c_wait_while_bb(oadap);				DEB0("Arbitration lost, retrying transfer");				break;			}			if (status & I2C_STAT_NACK) {				i2c_reg_out(oadap, I2C_STAT, I2C_STAT_NACK);				DEB0("I2C xfer aborted by NAK");				return -EREMOTEIO;			}			if (status & I2C_STAT_ARDY) {				i2c_reg_out(oadap, I2C_STAT, I2C_STAT_ARDY);				if (count == msg->len) {					/* successful completion of transfer */					DEB2("I2C xfer complete");					return count;				}				else {					DEB0("I2C transfer ended prematurely");					return -EREMOTEIO;				}			}			if (status & I2C_STAT_XRDY) {				if (msg->flags & I2C_M_RD) {					DEB0("Unexpected tx request during I2C"					     " read");					return -EREMOTEIO;				}				if (count < msg->len) {					data = msg->buf[count++];					if (count < msg->len)						data |= msg->buf[count++] << 8;					i2c_reg_out(oadap, I2C_DATA, data);					i2c_reg_out(oadap, I2C_STAT, 						I2C_STAT_XRDY);					DEB2("I2C data word tx");				}				else {					i2c_reg_out(oadap, I2C_STAT, 						I2C_STAT_XRDY);					DEB0("I2C tx past end of message");					return -EREMOTEIO;				}			}			if (status & I2C_STAT_RRDY) {				if (!(msg->flags & I2C_M_RD)) {					DEB0("Unexpected rx request during I2C"					     " write");					return -EREMOTEIO;				}				if (count < msg->len) {					data = i2c_reg_in(oadap, I2C_DATA);					msg->buf[count++] = (u8) data;					if (count < msg->len) {						msg->buf[count++] = 							(u8) (data >> 8);					}					i2c_reg_out(oadap, I2C_STAT, 						I2C_STAT_RRDY);					DEB2("I2C data word rx");				}				else {					i2c_reg_out(oadap, I2C_STAT, 						I2C_STAT_RRDY);					DEB0("I2C rx past end of message");					return -EREMOTEIO;				}			}		}	}	DEB0("Retry limit reached--I2C xfer aborted");	return -EREMOTEIO;}/* * Read or write to an I2C device.  Returns num if all messages are transferred  * successfully, or a negative error code otherwise. */static intomap24xx_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num){	struct omap24xx_i2c_adapter *oadap = 		(struct omap24xx_i2c_adapter *) adap->algo_data;	struct i2c_msg *pmsg;	int i, ret;	if (i2c_wait_while_bb(oadap)) {		/* The bus is still busy.  We're going to reset our I2C bus 		 * controller and then go ahead with our transfer regardless.		 */		DEB0("Resetting I2C controller.");		i2c_hw_init(oadap);	}	for (i=0; i < num; i++) {		pmsg = &msgs[i];		ret = omap24xx_i2c_xfer_msg(oadap, pmsg, (i == (num - 1)));		if (ret < pmsg->len) {			DEB0("I2C transfer failed.  Resetting I2C controller.");			i2c_hw_init(oadap);			return (ret < 0) ? ret : -EREMOTEIO;		}	}	return num;}static u32omap24xx_i2c_func(struct i2c_adapter *adap){	/* We delete I2C_FUNC_SMBUS_QUICK from our list of capabilities 	 * because that requires the ability to generate messages with 	 * zero bytes of data.  The OMAP I2C controller is not able to do 	 * this.  The lack of this feature prevents probing for I2C devices.	 */	return (((I2C_FUNC_SMBUS_EMUL) & ~(I2C_FUNC_SMBUS_QUICK))	       | I2C_FUNC_10BIT_ADDR);}/* -----exported algorithm data: -------------------------------------	*/static struct i2c_algorithm omap24xx_i2c_algo = {	.name = "OMAP24xx I2C algorithm",	.id = I2C_ALGO_EXP,	.master_xfer = omap24xx_i2c_xfer,	.functionality = omap24xx_i2c_func,};/*  * registering functions to load algorithms at runtime  */static intomap24xx_i2c_add_bus(struct i2c_adapter *adap){	adap->id |= omap24xx_i2c_algo.id;	adap->algo = &omap24xx_i2c_algo;	adap->timeout = (I2C_DEFAULT_TIMEOUT_MS*HZ + 999)/1000 + 1;	adap->retries = 2;	adap->class = I2C_CLASS_HWMON;	return i2c_add_adapter(adap);}static intomap24xx_i2c_del_bus(struct i2c_adapter *adap){	return i2c_del_adapter(adap);}void omap24xx_i2c_exit(void){	struct omap24xx_i2c_adapter *oadap;	struct i2c_adapter *adap;	int i;	for (i = NUM_I2C_ADAP - 1; i >= 0; i--) {		oadap = saved_oadap[i];		if (!oadap)			continue;		adap = &oadap->adap;		if (adap->dev.bus_id[0]) {			omap24xx_i2c_del_bus(adap);			adap->dev.bus_id[0] = '\0';		}		if (oadap->irq) {			free_irq(oadap->irq, oadap);			oadap->irq = 0;		}		i2c_hw_release(oadap);		if (oadap->mmio_base) {			iounmap((void *)oadap->mmio_base);			oadap->mmio_base = 0;		}		if (oadap->mmio_base_phys) {			release_mem_region(oadap->mmio_base_phys, 				oadap->mmio_size);			oadap->mmio_base_phys = 0;		}		kfree(oadap);		saved_oadap[i] = NULL;	}}int __initomap24xx_i2c_init(void){	struct omap24xx_i2c_adapter *oadap;	struct i2c_adapter *adap;	int i;	unsigned long reg_val;	const static unsigned long reg_addr[] = 		{ I2C1_REG_BASE, I2C2_REG_BASE };	const static unsigned long reg_size[] = 		{ I2C1_REG_SIZE, I2C2_REG_SIZE };	const static int i2c_irq[] = { INT_I2C1_IRQ, INT_I2C2_IRQ };	const static char *i2c_name[] = { I2C_NAME "-1", I2C_NAME "-2" };	/* Mux support and PRCM Initilization */	omap2_cfg_reg(M19_2420_I2C1_SCL);        omap2_cfg_reg(L15_2420_I2C1_SDA);        reg_val = omap_prcmreg_read(PRCM_FCLK_EN2_CORE);        omap_prcmreg_write(reg_val | ( 1<<20 | 1<<19 ) ,PRCM_FCLK_EN2_CORE);        reg_val = omap_prcmreg_read(PRCM_ICLK_EN2_CORE);        omap_prcmreg_write(reg_val | ( 1<<20 | 1<<19 ) ,PRCM_ICLK_EN2_CORE);		if (i2c_clock > 200)		i2c_clock = 400;	/* Fast mode */	else		i2c_clock = 100;	/* Standard mode */	/* initialize each I2C controller */	for (i = 0; i < NUM_I2C_ADAP; i++) {		oadap = kmalloc(sizeof(struct omap24xx_i2c_adapter), 				GFP_KERNEL);		if (!oadap) {			printk(KERN_ERR I2C_NAME 				": could not allocate memory\n");			goto init_error;		}		memset(oadap, 0, sizeof(struct omap24xx_i2c_adapter));		saved_oadap[i] = oadap;		/* initialize the i2c_adapter struct */		adap = &oadap->adap;		adap->owner = THIS_MODULE;		adap->algo_data = oadap;		strlcpy(adap->name, i2c_name[i], sizeof(adap->name));		/* request the mem region */		if (!request_mem_region(reg_addr[i], reg_size[i], 			adap->name))		{			printk(KERN_ERR "%s: cannot reserve MMIO region\n", 				adap->name);			goto init_error;		}		oadap->mmio_base_phys = reg_addr[i];		oadap->mmio_size = reg_size[i];		/* map the region */		oadap->mmio_base = (unsigned long) 			ioremap(oadap->mmio_base_phys, oadap->mmio_size);		if (!oadap->mmio_base) {			printk(KERN_ERR "%s: cannot map MMIO\n", 				adap->name);			goto init_error;		}		init_waitqueue_head(&oadap->i2c_wait_queue);		if (i2c_hw_init(oadap) < 0) {			printk(KERN_ERR "%s: cannot reset I2C controller\n", 				adap->name);			goto init_error;		}		if (request_irq(i2c_irq[i], omap24xx_i2c_handler, 0, 			adap->name, oadap) < 0)		{			printk(KERN_ERR "%s: cannot intall handler for irq"				" %d\n", adap->name, i2c_irq[i]);			goto init_error;		}		oadap->irq = i2c_irq[i];		if (omap24xx_i2c_add_bus(adap) < 0) {			printk(KERN_ERR "%s: cannot register I2C adapter\n", 				adap->name);			adap->dev.bus_id[0] = '\0';			goto init_error;		}		printk(KERN_INFO "%s: I2C bus controller at 0x%08lx, irq %d,"			" registered as %s\n", 			adap->name, oadap->mmio_base_phys, oadap->irq, 			adap->dev.bus_id);	}	return 0;init_error:	/* call our exit routine to cleanup */	omap24xx_i2c_exit();	for (i = 0; i < NUM_I2C_ADAP; i++) {		printk(KERN_ERR "%s: I2C driver installation failed!\n", 			i2c_name[i]);	}	return -ENODEV;}MODULE_AUTHOR("MontaVista Software, Inc.");MODULE_DESCRIPTION("OMAP24xx I2C bus adapter");MODULE_LICENSE("GPL");module_param(i2c_clock, int, 0);MODULE_PARM_DESC(i2c_clock,		 "I2C clock in KHz: 100 (Standard Mode) or 400 (Fast Mode)");#ifdef I2C_OMAP24XX_DEBUGmodule_param(i2c_debug, int, 0);MODULE_PARM_DESC(i2c_debug,		 "debug level - 0 off; 1 normal; 2,3 more verbose; "		 "9 protocol");#endifmodule_init(omap24xx_i2c_init);module_exit(omap24xx_i2c_exit);

⌨️ 快捷键说明

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