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