/* * Prepare controller for a transaction and call omap_i2c_xfer_msg * to do the work during IRQ processing. */ static int omap_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; /* * hwspinlock is used to time share the I2C module between A9 and Ducati * on OMAP4. To avoid spurious IRQ due to I2C transaction initiated on * Ducati sub system I2C IRQ is enabled and disabled on i2c transfers. */ omap_i2c_hwspinlock_lock(dev); omap_i2c_unidle(dev); enable_irq(dev->irq); r = omap_i2c_wait_for_bb(dev); if (r < 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: disable_irq_nosync(dev->irq); omap_i2c_idle(dev); omap_i2c_hwspinlock_unlock(dev); return r; }
/* * Prepare controller for a transaction and call omap_i2c_xfer_msg * to do the work during IRQ processing. */ static int omap_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_unidle(dev); r = omap_i2c_wait_for_bb(dev); if (r < 0) goto out; if (dev->set_mpu_wkup_lat != NULL) dev->set_mpu_wkup_lat(dev->dev, dev->latency); for (i = 0; i < num; i++) { r = omap_i2c_xfer_msg(adap, &msgs[i], (i == (num - 1))); if (r != 0) break; } if (dev->set_mpu_wkup_lat != NULL) dev->set_mpu_wkup_lat(dev->dev, -1); if (r == 0) r = num; omap_i2c_wait_for_bb(dev); out: omap_i2c_idle(dev); return r; }
/* * Prepare controller for a transaction and call omap_i2c_xfer_msg * to do the work during IRQ processing. */ static int omap_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; struct platform_device *pdev; struct omap_i2c_bus_platform_data *pdata; pdev = container_of(dev->dev, struct platform_device, dev); pdata = pdev->dev.platform_data; /* * hwspinlock is used to time share the I2C module between A9 and Ducati * on OMAP4. To avoid spurious IRQ due to I2C transaction initiated on * Ducati sub system I2C IRQ is enabled and disabled on i2c transfers. */ omap_i2c_hwspinlock_lock(dev); spin_lock(&dev->dpll_lock); if (dev->dpll_entry == 1) { dev->dpll_entry = 0; /* * FIXME: Speed > 1000 can not be supported * in DPLL cascading mode. */ if (dev->speed > 1000) return -1; omap_i2c_dpll_configure(dev, pdata, OMAP_I2C_DPLL_CLOCK / 1000); } else if (dev->dpll_exit == 1) { dev->dpll_exit = 0; omap_i2c_dpll_configure(dev, pdata, dev->i2c_fclk_rate); } spin_unlock(&dev->dpll_lock); omap_i2c_unidle(dev); enable_irq(dev->irq); r = omap_i2c_wait_for_bb(dev); if (r < 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: disable_irq_nosync(dev->irq); omap_i2c_idle(dev); omap_i2c_hwspinlock_unlock(dev); return r; }
/* * Prepare controller for a transaction and call omap_i2c_xfer_msg * to do the work during IRQ processing. */ static int omap_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; if (dev == NULL) return -EINVAL; if (dev->shutdown) return -EPERM; r = omap_i2c_hwspinlock_lock(dev); /* To-Do: if we are unable to acquire the lock, we must try to recover somehow */ if (r != 0) return r; /* We have the bus, enable IRQ */ omap_i2c_unidle(dev); enable_irq(dev->irq); r = omap_i2c_wait_for_bb(dev); if (r < 0) r = omap_i2c_bus_clear(dev); if (r < 0) goto out; /* * When waiting for completion of a i2c transfer, we need to * set a wake up latency constraint for the MPU. This is to * ensure quick enough wakeup from idle, when transfer * completes. */ if (dev->pm_qos) pm_qos_update_request(dev->pm_qos, dev->latency); for (i = 0; i < num; i++) { r = omap_i2c_xfer_msg(adap, &msgs[i], (i == (num - 1))); if (r != 0) break; } if (dev->pm_qos) pm_qos_update_request(dev->pm_qos, PM_QOS_DEFAULT_VALUE); if (r == 0) r = num; omap_i2c_wait_for_bb(dev); out: disable_irq(dev->irq); omap_i2c_idle(dev); omap_i2c_hwspinlock_unlock(dev); return r; }
/* * Prepare controller for a transaction and call omap_i2c_xfer_msg * to do the work during IRQ processing. */ static int omap_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; //--[[ LGE_UBIQUIX_MODIFIED_START : [email protected] [2011.11.16] - In case a peripheral is holding the DATA bus low, reset the I2C controller u16 val; //--]] LGE_UBIQUIX_MODIFIED_END : [email protected] [2011.11.16]- In case a peripheral is holding the DATA bus low, reset the I2C controller /* * hwspinlock is used to time share the I2C module between A9 and Ducati * on OMAP4. To avoid spurious IRQ due to I2C transaction initiated on * Ducati sub system I2C IRQ is enabled and disabled on i2c transfers. */ omap_i2c_hwspinlock_lock(dev); omap_i2c_unidle(dev); enable_irq(dev->irq); r = omap_i2c_wait_for_bb(dev); //--[[ LGE_UBIQUIX_MODIFIED_START : [email protected] [2011.11.16] - In case a peripheral is holding the DATA bus low, reset the I2C controller /* If timeout, try to again check after soft reset of I2C block */ if (WARN_ON(r == -ETIMEDOUT)) { /* Provide a permanent clock to recover the peripheral */ val = omap_i2c_read_reg(dev, OMAP_I2C_SYSTEST_REG); val |= (OMAP_I2C_SYSTEST_ST_EN | OMAP_I2C_SYSTEST_FREE | (2 << OMAP_I2C_SYSTEST_TMODE_SHIFT)); omap_i2c_write_reg(dev, OMAP_I2C_SYSTEST_REG, val); msleep(1); omap_i2c_init(dev); r = omap_i2c_wait_for_bb(dev); } //--]] LGE_UBIQUIX_MODIFIED_END : [email protected] [2011.11.16]- In case a peripheral is holding the DATA bus low, reset the I2C controller if (r < 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; omap_i2c_wait_for_bb(dev); out: disable_irq_nosync(dev->irq); omap_i2c_idle(dev); omap_i2c_hwspinlock_unlock(dev); return r; }
/* * Prepare controller for a transaction and call omap_i2c_xfer_msg * to do the work during IRQ processing. */ static int omap_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; u16 val; omap_i2c_unidle(dev); r = omap_i2c_wait_for_bb(dev); /* If timeout, try to again check after soft reset of I2C block */ if (WARN_ON(r == -ETIMEDOUT)) { /* Provide a permanent clock to recover the peripheral */ val = omap_i2c_read_reg(dev, OMAP_I2C_SYSTEST_REG); val |= (OMAP_I2C_SYSTEST_ST_EN | OMAP_I2C_SYSTEST_FREE | (2 << OMAP_I2C_SYSTEST_TMODE_SHIFT)); omap_i2c_write_reg(dev, OMAP_I2C_SYSTEST_REG, val); msleep(1); omap_i2c_init(dev); r = omap_i2c_wait_for_bb(dev); } if (r < 0) goto out; /* * When waiting for completion of a i2c transfer, we need to * set a wake up latency constraint for the MPU. This is to * ensure quick enough wakeup from idle, when transfer * completes. */ if (dev->pm_qos) pm_qos_update_request(dev->pm_qos, dev->latency); for (i = 0; i < num; i++) { r = omap_i2c_xfer_msg(adap, &msgs[i], (i == (num - 1))); if (r != 0) break; } if (dev->pm_qos) pm_qos_update_request(dev->pm_qos, PM_QOS_DEFAULT_VALUE); if (r == 0) r = num; omap_i2c_wait_for_bb(dev); out: omap_i2c_idle(dev); return r; }
/* * Prepare controller for a transaction and call omap_i2c_xfer_msg * to do the work during IRQ processing. */ static int omap_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; u16 val; omap_i2c_unidle(dev); r = omap_i2c_wait_for_bb(dev); schedule_timeout_uninterruptible(5);// DCY - this seems to prevent lockup with Multi-Master system /* If timeout, try to again check after soft reset of I2C block */ if (WARN_ON(r == -ETIMEDOUT)) { /* Provide a permanent clock to recover the peripheral */ val = omap_i2c_read_reg(dev, OMAP_I2C_SYSTEST_REG); val |= (OMAP_I2C_SYSTEST_ST_EN | OMAP_I2C_SYSTEST_FREE | (2 << OMAP_I2C_SYSTEST_TMODE_SHIFT)); omap_i2c_write_reg(dev, OMAP_I2C_SYSTEST_REG, val); msleep(1); omap_i2c_init(dev); r = omap_i2c_wait_for_bb(dev); } if (r < 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; omap_i2c_wait_for_bb(dev); out: omap_i2c_idle(dev); return r; }
/* * Prepare controller for a transaction and call omap_i2c_xfer_msg * to do the work during IRQ processing. */ static int omap_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_unidle(dev); 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_idle(dev); return r; }
/* * Prepare controller for a transaction and call omap_i2c_xfer_msg * to do the work during IRQ processing. */ static int omap_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; #ifdef CONFIG_OMAP4_DPLL_CASCADING struct platform_device *pdev; struct omap_i2c_bus_platform_data *pdata; #endif if (dev == NULL) return -EINVAL; #ifdef CONFIG_OMAP4_DPLL_CASCADING pdev = container_of(dev->dev, struct platform_device, dev); pdata = pdev->dev.platform_data; #endif if (dev->shutdown) return -EPERM; r = omap_i2c_hwspinlock_lock(dev); /* To-Do: if we are unable to acquire the lock, we must try to recover somehow */ if (r != 0) return r; dev->got_lock = true; r = omap_i2c_unidle(dev); if ((r < 0) && (r != -ETIMEDOUT)) goto out_unlock; /* We have the bus, enable IRQ */ enable_irq(dev->irq); r = omap_i2c_wait_for_bb(dev); if (r < 0) r = omap_i2c_bus_clear(dev); if (r < 0) goto out; /* * When waiting for completion of a i2c transfer, we need to * set a wake up latency constraint for the MPU. This is to * ensure quick enough wakeup from idle, when transfer * completes. */ if (dev->pm_qos) pm_qos_update_request(dev->pm_qos, dev->latency); #ifdef CONFIG_OMAP4_DPLL_CASCADING spin_lock(&dev->dpll_lock); if (dev->dpll_entry == 1) { dev->dpll_entry = 0; /* * FIXME: Speed > 1000 can not be supported * in DPLL cascading mode. */ if (dev->speed > 1000) { spin_unlock(&dev->dpll_lock); return -1; } omap_i2c_dpll_configure(dev, pdata, OMAP_I2C_DPLL_CLOCK / 1000); } else if (dev->dpll_exit == 1) { dev->dpll_exit = 0; omap_i2c_dpll_configure(dev, pdata, dev->i2c_fclk_rate); } spin_unlock(&dev->dpll_lock); #endif for (i = 0; i < num; i++) { r = omap_i2c_xfer_msg(adap, &msgs[i], (i == (num - 1))); if (r != 0) break; } if (dev->pm_qos) pm_qos_update_request(dev->pm_qos, PM_QOS_DEFAULT_VALUE); if (r == 0) r = num; omap_i2c_wait_for_bb(dev); out: disable_irq(dev->irq); omap_i2c_idle(dev); out_unlock: omap_i2c_hwspinlock_unlock(dev); return r; }