summaryrefslogtreecommitdiff
path: root/linux
diff options
context:
space:
mode:
authorMauro Carvalho Chehab <mchehab@infradead.org>2007-05-22 00:37:58 -0300
committerMauro Carvalho Chehab <mchehab@infradead.org>2007-05-22 00:37:58 -0300
commit0d37212bd283bdd723e7285a4319e9ead3f7a94d (patch)
treebda986fd71fcd52bd5f22e9e6deb920f5b584a4c /linux
parent5f024c0eabb60488aa0826663ab3eb39c1e3aabe (diff)
downloadmediapointer-dvb-s2-0d37212bd283bdd723e7285a4319e9ead3f7a94d.tar.gz
mediapointer-dvb-s2-0d37212bd283bdd723e7285a4319e9ead3f7a94d.tar.bz2
Cafe_ccic: Properly power down the sensor
From: Jonathan Corbet <corbet@lwn.net> 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>
Diffstat (limited to 'linux')
-rw-r--r--linux/drivers/media/video/cafe_ccic-regs.h6
-rw-r--r--linux/drivers/media/video/cafe_ccic.c18
2 files changed, 23 insertions, 1 deletions
diff --git a/linux/drivers/media/video/cafe_ccic-regs.h b/linux/drivers/media/video/cafe_ccic-regs.h
index b2c22a0d6..8e2a87cdc 100644
--- a/linux/drivers/media/video/cafe_ccic-regs.h
+++ b/linux/drivers/media/video/cafe_ccic-regs.h
@@ -150,6 +150,12 @@
#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
diff --git a/linux/drivers/media/video/cafe_ccic.c b/linux/drivers/media/video/cafe_ccic.c
index 0615ec50c..4480df11e 100644
--- a/linux/drivers/media/video/cafe_ccic.c
+++ b/linux/drivers/media/video/cafe_ccic.c
@@ -782,6 +782,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.
* Control 1 is power down, set to 0 to operate.
@@ -791,6 +797,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)
@@ -799,6 +806,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);
}
@@ -858,6 +867,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;
}
@@ -2110,10 +2120,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);