#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/pci.h>
{
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);
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);
* Here we must wait a bit for the controller to come around.
*/
spin_unlock_irqrestore(&cam->dev_lock, flags);
- mdelay(5); /* FIXME revisit this */
+ msleep(5);
spin_lock_irqsave(&cam->dev_lock, flags);
cafe_reg_write(cam, REG_GL_CSR, GCSR_CCIC_EN|GCSR_SRC|GCSR_MRC);
spin_lock_irqsave(&cam->dev_lock, flags);
cafe_reg_clear_bit(cam, REG_CTRL1, C1_PWRDWN);
/*
+ * Part one of the sensor dance: turn the global
+ * GPIO signal on.
+ */
+ cafe_reg_write(cam, REG_GL_FCR, GFCR_GPIO_ON);
+ cafe_reg_write(cam, REG_GL_GPIOR, GGPIO_OUT|GGPIO_VAL);
+ /*
* Put the sensor into operational mode (assumes OLPC-style
* wiring). Control 0 is reset - set to 1 to operate.
* Control 1 is power down, set to 0 to operate.
cafe_reg_write(cam, REG_GPR, GPR_C1EN|GPR_C0EN|GPR_C0);
// mdelay(1); /* Enough? */
spin_unlock_irqrestore(&cam->dev_lock, flags);
+ msleep(5); /* Just to be sure */
}
static void cafe_ctlr_power_down(struct cafe_camera *cam)
spin_lock_irqsave(&cam->dev_lock, flags);
cafe_reg_write(cam, REG_GPR, GPR_C1EN|GPR_C0EN|GPR_C1);
+ cafe_reg_write(cam, REG_GL_FCR, GFCR_GPIO_ON);
+ cafe_reg_write(cam, REG_GL_GPIOR, GGPIO_OUT);
cafe_reg_set_bit(cam, REG_CTRL1, C1_PWRDWN);
spin_unlock_irqrestore(&cam->dev_lock, flags);
}
ret = 0;
cam->state = S_IDLE;
out:
+ cafe_ctlr_power_down(cam);
mutex_unlock(&cam->s_mutex);
return ret;
}
ret = request_irq(pdev->irq, cafe_irq, IRQF_SHARED, "cafe-ccic", cam);
if (ret)
goto out_iounmap;
+ /*
+ * Initialize the controller and leave it powered up. It will
+ * stay that way until the sensor driver shows up.
+ */
cafe_ctlr_init(cam);
cafe_ctlr_power_up(cam);
/*
- * Set up I2C/SMBUS communications
+ * Set up I2C/SMBUS communications. We have to drop the mutex here
+ * because the sensor could attach in this call chain, leading to
+ * unsightly deadlocks.
*/
mutex_unlock(&cam->s_mutex); /* attach can deadlock */
ret = cafe_smbus_setup(cam);
ret = pci_restore_state(pdev);
if (ret)
return ret;
- pci_enable_device(pdev);
+ ret = pci_enable_device(pdev);
+
+ if (ret) {
+ cam_warn(cam, "Unable to re-enable device on resume!\n");
+ return ret;
+ }
cafe_ctlr_init(cam);
- cafe_ctlr_power_up(cam);
+ cafe_ctlr_power_down(cam);
+
+ mutex_lock(&cam->s_mutex);
+ if (cam->users > 0) {
+ cafe_ctlr_power_up(cam);
+ __cafe_cam_reset(cam);
+ }
+ mutex_unlock(&cam->s_mutex);
+
set_bit(CF_CONFIG_NEEDED, &cam->flags);
if (cam->state == S_SPECREAD)
cam->state = S_IDLE; /* Don't bother restarting */