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 + -
显示快捷键?