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

📄 i2c-omap.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
			return 0;		if (stop) {			w = omap_i2c_read_reg(dev, OMAP_I2C_CON_REG);			w |= OMAP_I2C_CON_STP;			omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, w);		}		return -EREMOTEIO;	}	return -EIO;}/* * Prepare controller for a transaction and call omap_i2c_xfer_msg * to do the work during IRQ processing. */static intomap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num){	struct omap_i2c_dev *dev = i2c_get_adapdata(adap);	int i;	int r;	omap_i2c_enable_clocks(dev);	/* REVISIT: initialize and use adap->retries. This is an optional	 * feature */	if ((r = omap_i2c_wait_for_bb(dev)) < 0)		goto out;	for (i = 0; i < num; i++) {		r = omap_i2c_xfer_msg(adap, &msgs[i], (i == (num - 1)));		if (r != 0)			break;	}	if (r == 0)		r = num;out:	omap_i2c_disable_clocks(dev);	return r;}static u32omap_i2c_func(struct i2c_adapter *adap){	return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);}static inline voidomap_i2c_complete_cmd(struct omap_i2c_dev *dev, u16 err){	dev->cmd_err |= err;	complete(&dev->cmd_complete);}static inline voidomap_i2c_ack_stat(struct omap_i2c_dev *dev, u16 stat){	omap_i2c_write_reg(dev, OMAP_I2C_STAT_REG, stat);}static irqreturn_tomap_i2c_rev1_isr(int this_irq, void *dev_id){	struct omap_i2c_dev *dev = dev_id;	u16 iv, w;	iv = omap_i2c_read_reg(dev, OMAP_I2C_IV_REG);	switch (iv) {	case 0x00:	/* None */		break;	case 0x01:	/* Arbitration lost */		dev_err(dev->dev, "Arbitration lost\n");		omap_i2c_complete_cmd(dev, OMAP_I2C_STAT_AL);		break;	case 0x02:	/* No acknowledgement */		omap_i2c_complete_cmd(dev, OMAP_I2C_STAT_NACK);		omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_STP);		break;	case 0x03:	/* Register access ready */		omap_i2c_complete_cmd(dev, 0);		break;	case 0x04:	/* Receive data ready */		if (dev->buf_len) {			w = omap_i2c_read_reg(dev, OMAP_I2C_DATA_REG);			*dev->buf++ = w;			dev->buf_len--;			if (dev->buf_len) {				*dev->buf++ = w >> 8;				dev->buf_len--;			}		} else			dev_err(dev->dev, "RRDY IRQ while no data requested\n");		break;	case 0x05:	/* Transmit data ready */		if (dev->buf_len) {			w = *dev->buf++;			dev->buf_len--;			if (dev->buf_len) {				w |= *dev->buf++ << 8;				dev->buf_len--;			}			omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w);		} else			dev_err(dev->dev, "XRDY IRQ while no data to send\n");		break;	default:		return IRQ_NONE;	}	return IRQ_HANDLED;}static irqreturn_tomap_i2c_isr(int this_irq, void *dev_id){	struct omap_i2c_dev *dev = dev_id;	u16 bits;	u16 stat, w;	int count = 0;	bits = omap_i2c_read_reg(dev, OMAP_I2C_IE_REG);	while ((stat = (omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG))) & bits) {		dev_dbg(dev->dev, "IRQ (ISR = 0x%04x)\n", stat);		if (count++ == 100) {			dev_warn(dev->dev, "Too much work in one IRQ\n");			break;		}		omap_i2c_write_reg(dev, OMAP_I2C_STAT_REG, stat);		if (stat & OMAP_I2C_STAT_ARDY) {			omap_i2c_complete_cmd(dev, 0);			continue;		}		if (stat & OMAP_I2C_STAT_RRDY) {			w = omap_i2c_read_reg(dev, OMAP_I2C_DATA_REG);			if (dev->buf_len) {				*dev->buf++ = w;				dev->buf_len--;				if (dev->buf_len) {					*dev->buf++ = w >> 8;					dev->buf_len--;				}			} else				dev_err(dev->dev, "RRDY IRQ while no data "						"requested\n");			omap_i2c_ack_stat(dev, OMAP_I2C_STAT_RRDY);			continue;		}		if (stat & OMAP_I2C_STAT_XRDY) {			w = 0;			if (dev->buf_len) {				w = *dev->buf++;				dev->buf_len--;				if (dev->buf_len) {					w |= *dev->buf++ << 8;					dev->buf_len--;				}			} else				dev_err(dev->dev, "XRDY IRQ while no "					"data to send\n");			omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w);			omap_i2c_ack_stat(dev, OMAP_I2C_STAT_XRDY);			continue;		}		if (stat & OMAP_I2C_STAT_ROVR) {			dev_err(dev->dev, "Receive overrun\n");			dev->cmd_err |= OMAP_I2C_STAT_ROVR;		}		if (stat & OMAP_I2C_STAT_XUDF) {			dev_err(dev->dev, "Transmit overflow\n");			dev->cmd_err |= OMAP_I2C_STAT_XUDF;		}		if (stat & OMAP_I2C_STAT_NACK) {			omap_i2c_complete_cmd(dev, OMAP_I2C_STAT_NACK);			omap_i2c_write_reg(dev, OMAP_I2C_CON_REG,					   OMAP_I2C_CON_STP);		}		if (stat & OMAP_I2C_STAT_AL) {			dev_err(dev->dev, "Arbitration lost\n");			omap_i2c_complete_cmd(dev, OMAP_I2C_STAT_AL);		}	}	return count ? IRQ_HANDLED : IRQ_NONE;}static const struct i2c_algorithm omap_i2c_algo = {	.master_xfer	= omap_i2c_xfer,	.functionality	= omap_i2c_func,};static intomap_i2c_probe(struct platform_device *pdev){	struct omap_i2c_dev	*dev;	struct i2c_adapter	*adap;	struct resource		*mem, *irq, *ioarea;	int r;	/* NOTE: driver uses the static register mapping */	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);	if (!mem) {		dev_err(&pdev->dev, "no mem resource?\n");		return -ENODEV;	}	irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);	if (!irq) {		dev_err(&pdev->dev, "no irq resource?\n");		return -ENODEV;	}	ioarea = request_mem_region(mem->start, (mem->end - mem->start) + 1,			pdev->name);	if (!ioarea) {		dev_err(&pdev->dev, "I2C region already claimed\n");		return -EBUSY;	}	if (clock > 200)		clock = 400;	/* Fast mode */	else		clock = 100;	/* Standard mode */	dev = kzalloc(sizeof(struct omap_i2c_dev), GFP_KERNEL);	if (!dev) {		r = -ENOMEM;		goto err_release_region;	}	dev->dev = &pdev->dev;	dev->irq = irq->start;	dev->base = (void __iomem *) IO_ADDRESS(mem->start);	platform_set_drvdata(pdev, dev);	if ((r = omap_i2c_get_clocks(dev)) != 0)		goto err_free_mem;	omap_i2c_enable_clocks(dev);	if (cpu_is_omap15xx())		dev->rev1 = omap_i2c_read_reg(dev, OMAP_I2C_REV_REG) < 0x20;	/* reset ASAP, clearing any IRQs */	omap_i2c_init(dev);	r = request_irq(dev->irq, dev->rev1 ? omap_i2c_rev1_isr : omap_i2c_isr,			0, pdev->name, dev);	if (r) {		dev_err(dev->dev, "failure requesting irq %i\n", dev->irq);		goto err_unuse_clocks;	}	r = omap_i2c_read_reg(dev, OMAP_I2C_REV_REG) & 0xff;	dev_info(dev->dev, "bus %d rev%d.%d at %d kHz\n",		 pdev->id, r >> 4, r & 0xf, clock);	adap = &dev->adapter;	i2c_set_adapdata(adap, dev);	adap->owner = THIS_MODULE;	adap->class = I2C_CLASS_HWMON;	strncpy(adap->name, "OMAP I2C adapter", sizeof(adap->name));	adap->algo = &omap_i2c_algo;	adap->dev.parent = &pdev->dev;	/* i2c device drivers may be active on return from add_adapter() */	adap->nr = pdev->id;	r = i2c_add_numbered_adapter(adap);	if (r) {		dev_err(dev->dev, "failure adding adapter\n");		goto err_free_irq;	}	omap_i2c_disable_clocks(dev);	return 0;err_free_irq:	free_irq(dev->irq, dev);err_unuse_clocks:	omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);	omap_i2c_disable_clocks(dev);	omap_i2c_put_clocks(dev);err_free_mem:	platform_set_drvdata(pdev, NULL);	kfree(dev);err_release_region:	release_mem_region(mem->start, (mem->end - mem->start) + 1);	return r;}static intomap_i2c_remove(struct platform_device *pdev){	struct omap_i2c_dev	*dev = platform_get_drvdata(pdev);	struct resource		*mem;	platform_set_drvdata(pdev, NULL);	free_irq(dev->irq, dev);	i2c_del_adapter(&dev->adapter);	omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);	omap_i2c_put_clocks(dev);	kfree(dev);	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);	release_mem_region(mem->start, (mem->end - mem->start) + 1);	return 0;}static struct platform_driver omap_i2c_driver = {	.probe		= omap_i2c_probe,	.remove		= omap_i2c_remove,	.driver		= {		.name	= "i2c_omap",		.owner	= THIS_MODULE,	},};/* I2C may be needed to bring up other drivers */static int __initomap_i2c_init_driver(void){	return platform_driver_register(&omap_i2c_driver);}subsys_initcall(omap_i2c_init_driver);static void __exit omap_i2c_exit_driver(void){	platform_driver_unregister(&omap_i2c_driver);}module_exit(omap_i2c_exit_driver);MODULE_AUTHOR("MontaVista Software, Inc. (and others)");MODULE_DESCRIPTION("TI OMAP I2C bus adapter");MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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