/* * Waiting for bus not busy */ static int i2c_davinci_wait_bus_not_busy(struct davinci_i2c_dev *dev, char allow_sleep) { unsigned long timeout; static rt_uint16_t to_cnt; timeout = rt_tick_get() + dev->bus->timeout; while (davinci_i2c_read_reg(dev, DAVINCI_I2C_STR_REG) & DAVINCI_I2C_STR_BB) { if (to_cnt <= DAVINCI_I2C_MAX_TRIES) { if (rt_tick_get() >= timeout) { rt_kprintf("timeout waiting for bus ready\n"); to_cnt++; return -RT_ETIMEOUT; } else { to_cnt = 0; i2c_recover_bus(dev); i2c_davinci_init(dev); } } if (allow_sleep) rt_thread_delay(2); } return 0; }
/* * Waiting on Bus Busy */ static int omap_i2c_wait_for_bb(struct omap_i2c_dev *dev) { unsigned long timeout; timeout = jiffies + OMAP_I2C_TIMEOUT; while (omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG) & OMAP_I2C_STAT_BB) { if (time_after(jiffies, timeout)) return i2c_recover_bus(&dev->adapter); msleep(1); } return 0; }
static int i2c_fsl_start(struct i2c_adapter *adapter) { struct fsl_i2c_struct *i2c_fsl = to_fsl_i2c_struct(adapter); unsigned int temp = 0; int result; fsl_i2c_write_reg(i2c_fsl->ifdr, i2c_fsl, FSL_I2C_IFDR); #ifdef CONFIG_PPC if (i2c_fsl->dfsrr != -1) fsl_i2c_write_reg(i2c_fsl->dfsrr, i2c_fsl, FSL_I2C_DFSRR); #endif /* Enable I2C controller */ fsl_i2c_write_reg(i2c_fsl->hwdata->i2sr_clr_opcode, i2c_fsl, FSL_I2C_I2SR); fsl_i2c_write_reg(i2c_fsl->hwdata->i2cr_ien_opcode, i2c_fsl, FSL_I2C_I2CR); /* Wait controller to be stable */ udelay(100); /* Start I2C transaction */ temp = fsl_i2c_read_reg(i2c_fsl, FSL_I2C_I2CR); temp |= I2CR_MSTA; fsl_i2c_write_reg(temp, i2c_fsl, FSL_I2C_I2CR); result = i2c_fsl_bus_busy(adapter, 1); if (result) { result = i2c_recover_bus(&i2c_fsl->adapter); if (result) return result; return -EAGAIN; } i2c_fsl->stopped = 0; temp |= I2CR_MTX | I2CR_TXAK; fsl_i2c_write_reg(temp, i2c_fsl, FSL_I2C_I2CR); return result; }
static int uniphier_i2c_check_bus_busy(struct i2c_adapter *adap) { struct uniphier_i2c_priv *priv = i2c_get_adapdata(adap); if (!(readl(priv->membase + UNIPHIER_I2C_DREC) & UNIPHIER_I2C_DREC_BBN)) { if (priv->busy_cnt++ > 3) { /* * If bus busy continues too long, it is probably * in a wrong state. Try bus recovery. */ i2c_recover_bus(adap); priv->busy_cnt = 0; } return -EAGAIN; } priv->busy_cnt = 0; return 0; }
static int uniphier_i2c_master_xfer_one(struct i2c_adapter *adap, struct i2c_msg *msg, bool stop) { bool is_read = msg->flags & I2C_M_RD; bool recovery = false; int ret; dev_dbg(&adap->dev, "%s: addr=0x%02x, len=%d, stop=%d\n", is_read ? "receive" : "transmit", msg->addr, msg->len, stop); if (is_read) ret = uniphier_i2c_rx(adap, msg->addr, msg->len, msg->buf); else ret = uniphier_i2c_tx(adap, msg->addr, msg->len, msg->buf); if (ret == -EAGAIN) /* could not acquire bus. bail out without STOP */ return ret; if (ret == -ETIMEDOUT) { /* This error is fatal. Needs recovery. */ stop = false; recovery = true; } if (stop) { int ret2 = uniphier_i2c_stop(adap); if (ret2) { /* Failed to issue STOP. The bus needs recovery. */ recovery = true; ret = ret ?: ret2; } } if (recovery) i2c_recover_bus(adap); return ret; }
static int i2c_fsl_start(struct i2c_adapter *adapter) { struct fsl_i2c_struct *i2c_fsl = to_fsl_i2c_struct(adapter); void __iomem *base = i2c_fsl->base; unsigned int temp = 0; int result; writeb(i2c_fsl->ifdr, base + FSL_I2C_IFDR); if (i2c_fsl->dfsrr != -1) writeb(i2c_fsl->dfsrr, base + FSL_I2C_DFSRR); /* Enable I2C controller */ writeb(0, base + FSL_I2C_I2SR); writeb(I2CR_IEN, base + FSL_I2C_I2CR); /* Wait controller to be stable */ udelay(100); /* Start I2C transaction */ temp = readb(base + FSL_I2C_I2CR); temp |= I2CR_MSTA; writeb(temp, base + FSL_I2C_I2CR); result = i2c_fsl_bus_busy(adapter, 1); if (result) { result = i2c_recover_bus(&i2c_fsl->adapter); if (result) return result; return -EAGAIN; } i2c_fsl->stopped = 0; temp |= I2CR_MTX | I2CR_TXAK; writeb(temp, base + FSL_I2C_I2CR); return result; }
/* * Prepare controller for a transaction and call i2c_dw_xfer_msg. */ static int i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) { struct dw_i2c_dev *dev = i2c_get_adapdata(adap); int ret; dev_dbg(dev->dev, "%s: msgs: %d\n", __func__, num); pm_runtime_get_sync(dev->dev); if (dev_WARN_ONCE(dev->dev, dev->suspended, "Transfer while suspended\n")) { ret = -ESHUTDOWN; goto done_nolock; } reinit_completion(&dev->cmd_complete); dev->msgs = msgs; dev->msgs_num = num; dev->cmd_err = 0; dev->msg_write_idx = 0; dev->msg_read_idx = 0; dev->msg_err = 0; dev->status = STATUS_IDLE; dev->abort_source = 0; dev->rx_outstanding = 0; ret = i2c_dw_acquire_lock(dev); if (ret) goto done_nolock; ret = i2c_dw_wait_bus_not_busy(dev); if (ret < 0) goto done; /* Start the transfers */ i2c_dw_xfer_init(dev); /* Wait for tx to complete */ if (!wait_for_completion_timeout(&dev->cmd_complete, adap->timeout)) { dev_err(dev->dev, "controller timed out\n"); /* i2c_dw_init implicitly disables the adapter */ i2c_recover_bus(&dev->adapter); i2c_dw_init_master(dev); ret = -ETIMEDOUT; goto done; } /* * We must disable the adapter before returning and signaling the end * of the current transfer. Otherwise the hardware might continue * generating interrupts which in turn causes a race condition with * the following transfer. Needs some more investigation if the * additional interrupts are a hardware bug or this driver doesn't * handle them correctly yet. */ __i2c_dw_disable_nowait(dev); if (dev->msg_err) { ret = dev->msg_err; goto done; } /* No error */ if (likely(!dev->cmd_err && !dev->status)) { ret = num; goto done; } /* We have an error */ if (dev->cmd_err == DW_IC_ERR_TX_ABRT) { ret = i2c_dw_handle_tx_abort(dev); goto done; } if (dev->status) dev_err(dev->dev, "transfer terminated early - interrupt latency too high?\n"); ret = -EIO; done: i2c_dw_release_lock(dev); done_nolock: pm_runtime_mark_last_busy(dev->dev); pm_runtime_put_autosuspend(dev->dev); return ret; }
static void uniphier_fi2c_recover(struct uniphier_fi2c_priv *priv) { uniphier_fi2c_reset(priv); i2c_recover_bus(&priv->adap); }
/* * Low level master read/write transaction. This function is called * from i2c_davinci_xfer. */ static int i2c_davinci_xfer_msg(struct rt_i2c_bus_device *bus, struct rt_i2c_msg *msg, int stop) { struct davinci_i2c_dev *dev = bus->priv; rt_uint32_t flag; rt_uint16_t w; int r; /* Introduce a delay, required for some boards (e.g Davinci EVM) */ if (dev->bus_delay) udelay(dev->bus_delay); /* set the slave address */ davinci_i2c_write_reg(dev, DAVINCI_I2C_SAR_REG, msg->addr); dev->buf = msg->buf; dev->buf_len = msg->len; dev->stop = stop; davinci_i2c_write_reg(dev, DAVINCI_I2C_CNT_REG, dev->buf_len); //INIT_COMPLETION(dev->cmd_complete); dev->cmd_err = 0; /* Take I2C out of reset and configure it as master */ flag = DAVINCI_I2C_MDR_IRS | DAVINCI_I2C_MDR_MST; /* if the slave address is ten bit address, enable XA bit */ if (msg->flags & RT_I2C_ADDR_10BIT) flag |= DAVINCI_I2C_MDR_XA; if (!(msg->flags & RT_I2C_RD)) flag |= DAVINCI_I2C_MDR_TRX; if (msg->len == 0) flag |= DAVINCI_I2C_MDR_RM; /* Enable receive or transmit interrupts */ w = davinci_i2c_read_reg(dev, DAVINCI_I2C_IMR_REG); if (msg->flags & RT_I2C_RD) w |= DAVINCI_I2C_IMR_RRDY; else w |= DAVINCI_I2C_IMR_XRDY; davinci_i2c_write_reg(dev, DAVINCI_I2C_IMR_REG, w); dev->terminate = 0; /* * Write mode register first as needed for correct behaviour * on OMAP-L138, but don't set STT yet to avoid a race with XRDY * occurring before we have loaded DXR */ davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, flag); /* * First byte should be set here, not after interrupt, * because transmit-data-ready interrupt can come before * NACK-interrupt during sending of previous message and * ICDXR may have wrong data * It also saves us one interrupt, slightly faster */ if ((!(msg->flags & RT_I2C_RD)) && dev->buf_len) { davinci_i2c_write_reg(dev, DAVINCI_I2C_DXR_REG, *dev->buf++); dev->buf_len--; } /* Set STT to begin transmit now DXR is loaded */ flag |= DAVINCI_I2C_MDR_STT; if (stop && msg->len != 0) flag |= DAVINCI_I2C_MDR_STP; davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, flag); r = rt_sem_take(&dev->completion, dev->bus->timeout); if (r == -RT_ETIMEOUT) { rt_kprintf("controller timed out\n"); i2c_recover_bus(dev); i2c_davinci_init(dev); dev->buf_len = 0; return -RT_ETIMEOUT; } if (dev->buf_len) { /* This should be 0 if all bytes were transferred * or dev->cmd_err denotes an error. * A signal may have aborted the transfer. */ if (r == RT_EOK) { rt_kprintf("abnormal termination buf_len=%i\n", dev->buf_len); r = -RT_EIO; } dev->terminate = 1; dev->buf_len = 0; } if (r < 0) return r; /* no error */ if (!dev->cmd_err) return msg->len; /* We have an error */ if (dev->cmd_err & DAVINCI_I2C_STR_AL) { i2c_davinci_init(dev); return -RT_EIO; } if (dev->cmd_err & DAVINCI_I2C_STR_NACK) { if (msg->flags & RT_I2C_IGNORE_NACK) return msg->len; if (stop) { w = davinci_i2c_read_reg(dev, DAVINCI_I2C_MDR_REG); w |= DAVINCI_I2C_MDR_STP; davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, w); } return -RT_EIO; } return -RT_EIO; }