/** * i2c_pnx_xfer - generic transfer entry point * @adap: pointer to I2C adapter structure * @msgs: array of messages * @num: number of messages * * Initiates the transfer */ static int i2c_pnx_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) { struct i2c_msg *pmsg; int rc = 0, completed = 0, i; struct i2c_pnx_algo_data *alg_data = adap->algo_data; u32 stat = ioread32(I2C_REG_STS(alg_data)); dev_dbg(&alg_data->adapter.dev, "%s(): entering: %d messages, stat = %04x.\n", __func__, num, ioread32(I2C_REG_STS(alg_data))); bus_reset_if_active(alg_data); /* Process transactions in a loop. */ for (i = 0; rc >= 0 && i < num; i++) { u8 addr; pmsg = &msgs[i]; addr = pmsg->addr; if (pmsg->flags & I2C_M_TEN) { dev_err(&alg_data->adapter.dev, "%s: 10 bits addr not supported!\n", alg_data->adapter.name); rc = -EINVAL; break; } alg_data->mif.buf = pmsg->buf; alg_data->mif.len = pmsg->len; alg_data->mif.order = pmsg->len; alg_data->mif.mode = (pmsg->flags & I2C_M_RD) ? I2C_SMBUS_READ : I2C_SMBUS_WRITE; alg_data->mif.ret = 0; alg_data->last = (i == num - 1); dev_dbg(&alg_data->adapter.dev, "%s(): mode %d, %d bytes\n", __func__, alg_data->mif.mode, alg_data->mif.len); i2c_pnx_arm_timer(alg_data); /* initialize the completion var */ init_completion(&alg_data->mif.complete); /* Enable master interrupt */ iowrite32(ioread32(I2C_REG_CTL(alg_data)) | mcntrl_afie | mcntrl_naie | mcntrl_drmie, I2C_REG_CTL(alg_data)); /* Put start-code and slave-address on the bus. */ rc = i2c_pnx_start(addr, alg_data); if (rc < 0) break; /* Wait for completion */ wait_for_completion(&alg_data->mif.complete); if (!(rc = alg_data->mif.ret)) completed++; dev_dbg(&alg_data->adapter.dev, "%s(): Complete, return code = %d.\n", __func__, rc); /* Clear TDI and AFI bits in case they are set. */ if ((stat = ioread32(I2C_REG_STS(alg_data))) & mstatus_tdi) { dev_dbg(&alg_data->adapter.dev, "%s: TDI still set... clearing now.\n", alg_data->adapter.name); iowrite32(stat, I2C_REG_STS(alg_data)); } if ((stat = ioread32(I2C_REG_STS(alg_data))) & mstatus_afi) { dev_dbg(&alg_data->adapter.dev, "%s: AFI still set... clearing now.\n", alg_data->adapter.name); iowrite32(stat, I2C_REG_STS(alg_data)); } } bus_reset_if_active(alg_data); /* Cleanup to be sure... */ alg_data->mif.buf = NULL; alg_data->mif.len = 0; alg_data->mif.order = 0; dev_dbg(&alg_data->adapter.dev, "%s(): exiting, stat = %x\n", __func__, ioread32(I2C_REG_STS(alg_data))); if (completed != num) return ((rc < 0) ? rc : -EREMOTEIO); return num; }
/* * Generic transfer entrypoint */ static int i2c_pnx_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) { struct i2c_msg *pmsg; int rc = 0, completed = 0, i; i2c_pnx_algo_data_t * alg_data = (i2c_pnx_algo_data_t *) adap->algo_data; pr_debug ("%s: Entered\n", __FUNCTION__); /* Give an error if we're suspended. */ if (adap->dev.parent->power.power_state) return -EBUSY; down(&alg_data->mif.sem); /* If the bus is still active, or there is already * data in one of the fifo's, there is something wrong. * Repair this by a reset ... */ if ((alg_data->master->sts & mstatus_active)) { alg_data->master->ctl |= mcntrl_reset; while (alg_data->master->ctl & mcntrl_reset); } else if (!(alg_data->master->sts & mstatus_rfe) || !(alg_data->master->sts & mstatus_tfe)) { printk(KERN_ERR "%s: FIFO's contain already data before xfer. Reset it ...\n", adap->name); alg_data->master->ctl |= mcntrl_reset; while (alg_data->master->ctl & mcntrl_reset); } /* Process transactions in a loop. */ for (i = 0; rc >= 0 && i < num;) { u8 addr; pmsg = &msgs[i++]; addr = pmsg->addr; if (pmsg->flags & I2C_M_TEN) { printk(KERN_ERR "%s: 10 bits addr not supported !\n", adap->name); rc = -EINVAL; break; } /* Check address for sanity. */ if (alg_data->slave && addr == alg_data->slave->adr) { printk("%s: An attempt was made to access our own slave address! :-)\n", adap->name); rc = -EINVAL; break; } /* Set up address and r/w bit */ if (pmsg->flags & I2C_M_REV_DIR_ADDR) { addr ^= 1; } alg_data->mif.buf = pmsg->buf; alg_data->mif.len = pmsg->len; alg_data->mif.mode = (pmsg->flags & I2C_M_RD) ? rcv : xmit; alg_data->mif.ret = 0; #if I2C_PNX010X_DEBUG pr_debug("%s: %s mode, %d bytes\n", __FUNCTION__, i2c_pnx_modestr[alg_data->mif.mode], alg_data->mif.len); #endif /* Arm timer */ i2c_pnx_arm_timer(&alg_data->mif.timer, (void *) alg_data); /* initialize the completion var */ init_completion(&alg_data->mif.complete); /* Enable master interrupt */ alg_data->master->ctl = mcntrl_afie | mcntrl_naie | mcntrl_drmie; /* Put start-code and slave-address on the bus. */ rc = i2c_pnx_start(addr, adap); if (0 != rc) { break; } pr_debug("%s(%d): stat = %04x, cntrl = %04x.\n", __FUNCTION__, __LINE__, alg_data->master->sts, alg_data->master->ctl); /* Wait for completion */ wait_for_completion(&alg_data->mif.complete); if (!(rc = alg_data->mif.ret)) completed++; pr_debug("%s: Return code = %d.\n", __FUNCTION__, rc); /* Clear TDI and AFI bits in case they are set. */ if (alg_data->master->sts & mstatus_tdi) { printk("%s: TDI still set ... clearing now.\n", adap->name); alg_data->master->sts |= mstatus_tdi; } if (alg_data->master->sts & mstatus_afi) { printk("%s: AFI still set ... clearing now.\n", adap->name); alg_data->master->sts |= mstatus_afi; } } /* If the bus is still active, reset it to prevent * corruption of future transactions. */ if ((alg_data->master->sts & mstatus_active)) { printk("%s: Bus is still active after xfer. Reset it ...\n", adap->name); alg_data->master->ctl |= mcntrl_reset; while (alg_data->master->ctl & mcntrl_reset); } else /* If there is data in the fifo's after transfer, * flush fifo's by reset. */ if (!(alg_data->master->sts & mstatus_rfe) || !(alg_data->master->sts & mstatus_tfe)) { alg_data->master->ctl |= mcntrl_reset; while (alg_data->master->ctl & mcntrl_reset); } else if ((alg_data->master->sts & mstatus_nai)) { alg_data->master->ctl |= mcntrl_reset; while (alg_data->master->ctl & mcntrl_reset); } /* Cleanup to be sure ... */ alg_data->mif.buf = NULL; alg_data->mif.len = 0; /* Release sem */ up(&alg_data->mif.sem); pr_debug ("%s: Exit\n", __FUNCTION__); if (completed != num) { return ((rc<0) ? rc : -EREMOTEIO); } return num ; }