Exemplo n.º 1
0
/*
 * 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;
}
Exemplo n.º 3
0
/*
 * 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;
}
Exemplo n.º 4
0
/*
 * 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;
}
Exemplo n.º 5
0
/*
 * 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;
}
Exemplo n.º 6
0
/*
 * 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;
}
Exemplo n.º 7
0
/*
 * 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;
}
Exemplo n.º 8
0
/*
 * 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;
}
Exemplo n.º 9
0
/*
 * 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;
}