V4L/DVB (5690): Cafe_ccic: Properly power down the sensor
authorJonathan Corbet <corbet@lwn.net>
Tue, 22 May 2007 03:37:58 +0000 (00:37 -0300)
committerMauro Carvalho Chehab <mchehab@infradead.org>
Tue, 22 May 2007 19:16:27 +0000 (16:16 -0300)
The proper method for powering down the sensor on OLPC systems has
changed somewhat; in particular, the sensor must be powered down
completely (rather than simply told to power down) or the associated
"camera active" LED will stay on.

Signed-off-by: Jonathan Corbet <corbet@lwn.net>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
drivers/media/video/cafe_ccic-regs.h
drivers/media/video/cafe_ccic.c

index b2c22a0d6643b49758deeb881d17abd15ef9fdac..8e2a87cdc791b1fa3018d9ee2fd0fef9f7283941 100644 (file)
 #define REG_GL_IMASK   0x300c  /* Interrupt mask register */
 #define   GIMSK_CCIC_EN          0x00000004    /* CCIC Interrupt enable */
 
+#define REG_GL_FCR     0x3038  /* GPIO functional control register */
+#define          GFCR_GPIO_ON    0x08          /* Camera GPIO enabled */
+#define REG_GL_GPIOR   0x315c  /* GPIO register */
+#define   GGPIO_OUT            0x80000 /* GPIO output */
+#define   GGPIO_VAL            0x00008 /* Output pin value */
+
 #define REG_LEN                REG_GL_IMASK + 4
 
 
index 96254dbaf6252f78de803f0b8e234ccc96830251..c08f650df42337df25a517eb7538e7a29c9a8a8d 100644 (file)
@@ -774,6 +774,12 @@ static void cafe_ctlr_power_up(struct cafe_camera *cam)
 
        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.
@@ -784,6 +790,7 @@ static void cafe_ctlr_power_up(struct cafe_camera *cam)
        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)
@@ -792,6 +799,8 @@ 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);
 }
@@ -851,6 +860,7 @@ static int cafe_cam_init(struct cafe_camera *cam)
        ret = 0;
        cam->state = S_IDLE;
   out:
+       cafe_ctlr_power_down(cam);
        mutex_unlock(&cam->s_mutex);
        return ret;
 }
@@ -2103,10 +2113,16 @@ static int cafe_pci_probe(struct pci_dev *pdev,
        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);