Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

V4L/DVB (5690): Cafe_ccic: Properly power down the sensor

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>

authored by

Jonathan Corbet and committed by
Mauro Carvalho Chehab
7acf90c7 82c01d3d

+23 -1
+6
drivers/media/video/cafe_ccic-regs.h
··· 150 150 #define REG_GL_IMASK 0x300c /* Interrupt mask register */ 151 151 #define GIMSK_CCIC_EN 0x00000004 /* CCIC Interrupt enable */ 152 152 153 + #define REG_GL_FCR 0x3038 /* GPIO functional control register */ 154 + #define GFCR_GPIO_ON 0x08 /* Camera GPIO enabled */ 155 + #define REG_GL_GPIOR 0x315c /* GPIO register */ 156 + #define GGPIO_OUT 0x80000 /* GPIO output */ 157 + #define GGPIO_VAL 0x00008 /* Output pin value */ 158 + 153 159 #define REG_LEN REG_GL_IMASK + 4 154 160 155 161
+17 -1
drivers/media/video/cafe_ccic.c
··· 775 775 spin_lock_irqsave(&cam->dev_lock, flags); 776 776 cafe_reg_clear_bit(cam, REG_CTRL1, C1_PWRDWN); 777 777 /* 778 + * Part one of the sensor dance: turn the global 779 + * GPIO signal on. 780 + */ 781 + cafe_reg_write(cam, REG_GL_FCR, GFCR_GPIO_ON); 782 + cafe_reg_write(cam, REG_GL_GPIOR, GGPIO_OUT|GGPIO_VAL); 783 + /* 778 784 * Put the sensor into operational mode (assumes OLPC-style 779 785 * wiring). Control 0 is reset - set to 1 to operate. 780 786 * Control 1 is power down, set to 0 to operate. ··· 790 784 cafe_reg_write(cam, REG_GPR, GPR_C1EN|GPR_C0EN|GPR_C0); 791 785 // mdelay(1); /* Enough? */ 792 786 spin_unlock_irqrestore(&cam->dev_lock, flags); 787 + msleep(5); /* Just to be sure */ 793 788 } 794 789 795 790 static void cafe_ctlr_power_down(struct cafe_camera *cam) ··· 799 792 800 793 spin_lock_irqsave(&cam->dev_lock, flags); 801 794 cafe_reg_write(cam, REG_GPR, GPR_C1EN|GPR_C0EN|GPR_C1); 795 + cafe_reg_write(cam, REG_GL_FCR, GFCR_GPIO_ON); 796 + cafe_reg_write(cam, REG_GL_GPIOR, GGPIO_OUT); 802 797 cafe_reg_set_bit(cam, REG_CTRL1, C1_PWRDWN); 803 798 spin_unlock_irqrestore(&cam->dev_lock, flags); 804 799 } ··· 860 851 ret = 0; 861 852 cam->state = S_IDLE; 862 853 out: 854 + cafe_ctlr_power_down(cam); 863 855 mutex_unlock(&cam->s_mutex); 864 856 return ret; 865 857 } ··· 2113 2103 ret = request_irq(pdev->irq, cafe_irq, IRQF_SHARED, "cafe-ccic", cam); 2114 2104 if (ret) 2115 2105 goto out_iounmap; 2106 + /* 2107 + * Initialize the controller and leave it powered up. It will 2108 + * stay that way until the sensor driver shows up. 2109 + */ 2116 2110 cafe_ctlr_init(cam); 2117 2111 cafe_ctlr_power_up(cam); 2118 2112 /* 2119 - * Set up I2C/SMBUS communications 2113 + * Set up I2C/SMBUS communications. We have to drop the mutex here 2114 + * because the sensor could attach in this call chain, leading to 2115 + * unsightly deadlocks. 2120 2116 */ 2121 2117 mutex_unlock(&cam->s_mutex); /* attach can deadlock */ 2122 2118 ret = cafe_smbus_setup(cam);