Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6d77444a authored by Jonathan Corbet's avatar Jonathan Corbet Committed by Mauro Carvalho Chehab
Browse files

V4L/DVB (6027): Get rid of an ill-behaved msleep in i2c write



Configuring the OLPC camera requires something over 150 register
writes.  Unfortunately, querying the CAFE i2c controller too
soon after a write causes the hardware to flake.  The problem had
been "solved" with an msleep() call, but, between the number of
registers and how msleep() behaves, that resulted in a 3-second
delay on camera initialization.  Instead, we hand-code a wait for
the completion interrupt which avoids reading the status registers.

Signed-off-by: default avatarJonathan Corbet <corbet@lwn.net>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@infradead.org>
parent 01659f2a
Loading
Loading
Loading
Loading
+21 −1
Original line number Diff line number Diff line
@@ -356,6 +356,7 @@ static int cafe_smbus_write_data(struct cafe_camera *cam,
{
	unsigned int rval;
	unsigned long flags;
	DEFINE_WAIT(the_wait);

	spin_lock_irqsave(&cam->dev_lock, flags);
	rval = TWSIC0_EN | ((addr << TWSIC0_SID_SHIFT) & TWSIC0_SID);
@@ -369,10 +370,29 @@ static int cafe_smbus_write_data(struct cafe_camera *cam,
	rval = value | ((command << TWSIC1_ADDR_SHIFT) & TWSIC1_ADDR);
	cafe_reg_write(cam, REG_TWSIC1, rval);
	spin_unlock_irqrestore(&cam->dev_lock, flags);
	msleep(2); /* Required or things flake */

	/*
	 * Time to wait for the write to complete.  THIS IS A RACY
	 * WAY TO DO IT, but the sad fact is that reading the TWSIC1
	 * register too quickly after starting the operation sends
	 * the device into a place that may be kinder and better, but
	 * which is absolutely useless for controlling the sensor.  In
	 * practice we have plenty of time to get into our sleep state
	 * before the interrupt hits, and the worst case is that we
	 * time out and then see that things completed, so this seems
	 * the best way for now.
	 */
	do {
		prepare_to_wait(&cam->smbus_wait, &the_wait,
				TASK_UNINTERRUPTIBLE);
		schedule_timeout(1); /* even 1 jiffy is too long */
		finish_wait(&cam->smbus_wait, &the_wait);
	} while (!cafe_smbus_write_done(cam));

#ifdef IF_THE_CAFE_HARDWARE_WORKED_RIGHT
	wait_event_timeout(cam->smbus_wait, cafe_smbus_write_done(cam),
			CAFE_SMBUS_TIMEOUT);
#endif
	spin_lock_irqsave(&cam->dev_lock, flags);
	rval = cafe_reg_read(cam, REG_TWSIC1);
	spin_unlock_irqrestore(&cam->dev_lock, flags);
+4 −1
Original line number Diff line number Diff line
@@ -416,7 +416,10 @@ static int ov7670_read(struct i2c_client *c, unsigned char reg,
static int ov7670_write(struct i2c_client *c, unsigned char reg,
		unsigned char value)
{
	return i2c_smbus_write_byte_data(c, reg, value);
	int ret = i2c_smbus_write_byte_data(c, reg, value);
	if (reg == REG_COM7 && (value & COM7_RESET))
		msleep(2);  /* Wait for reset to run */
	return ret;
}