diff options
Diffstat (limited to 'drivers/media')
-rw-r--r-- | drivers/media/video/cafe_ccic.c | 36 |
1 files changed, 17 insertions, 19 deletions
diff --git a/drivers/media/video/cafe_ccic.c b/drivers/media/video/cafe_ccic.c index 2ffb6df..05d810a 100644 --- a/drivers/media/video/cafe_ccic.c +++ b/drivers/media/video/cafe_ccic.c @@ -363,7 +363,6 @@ 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); @@ -378,28 +377,27 @@ static int cafe_smbus_write_data(struct cafe_camera *cam, cafe_reg_write(cam, REG_TWSIC1, rval); spin_unlock_irqrestore(&cam->dev_lock, flags); + /* Unfortunately, reading TWSIC1 too soon after sending a command + * causes the device to die. + * Use a busy-wait because we often send a large quantity of small + * commands at-once; using msleep() would cause a lot of context + * switches which take longer than 2ms, resulting in a noticable + * boot-time and capture-start delays. + */ + mdelay(2); + /* - * 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. + * Another sad fact is that sometimes, commands silently complete but + * cafe_smbus_write_done() never becomes aware of this. + * This happens at random and appears to possible occur with any + * command. + * We don't understand why this is. We work around this issue + * with the timeout in the wait below, assuming that all commands + * complete within the timeout. */ - 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); |