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