media: ov5647: Add support for PWDN GPIO.
authorDave Stevenson <dave.stevenson@raspberrypi.org>
Wed, 31 Oct 2018 14:56:33 +0000 (14:56 +0000)
committerpopcornmix <popcornmix@gmail.com>
Wed, 27 Jan 2021 19:12:57 +0000 (19:12 +0000)
Add support for an optional GPIO connected to PWDN on the sensor.

Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
drivers/media/i2c/ov5647.c

index 3e587eb..c39e3d2 100644 (file)
@@ -21,6 +21,7 @@
 
 #include <linux/clk.h>
 #include <linux/delay.h>
+#include <linux/gpio/consumer.h>
 #include <linux/i2c.h>
 #include <linux/init.h>
 #include <linux/io.h>
 
 #define SENSOR_NAME "ov5647"
 
+/*
+ * From the datasheet, "20ms after PWDN goes low or 20ms after RESETB goes
+ * high if reset is inserted after PWDN goes high, host can access sensor's
+ * SCCB to initialize sensor."
+ */
+#define PWDN_ACTIVE_DELAY_MS   20
+
 #define MIPI_CTRL00_CLOCK_LANE_GATE            BIT(5)
 #define MIPI_CTRL00_BUS_IDLE                   BIT(2)
 #define MIPI_CTRL00_CLOCK_LANE_DISABLE         BIT(0)
@@ -86,6 +94,7 @@ struct ov5647 {
        unsigned int                    height;
        int                             power_count;
        struct clk                      *xclk;
+       struct gpio_desc                *pwdn;
 };
 
 static inline struct ov5647 *to_state(struct v4l2_subdev *sd)
@@ -355,6 +364,11 @@ static int ov5647_sensor_power(struct v4l2_subdev *sd, int on)
        if (on && !ov5647->power_count) {
                dev_dbg(&client->dev, "OV5647 power on\n");
 
+               if (ov5647->pwdn) {
+                       gpiod_set_value(ov5647->pwdn, 0);
+                       msleep(PWDN_ACTIVE_DELAY_MS);
+               }
+
                ret = clk_prepare_enable(ov5647->xclk);
                if (ret < 0) {
                        dev_err(&client->dev, "clk prepare enable failed\n");
@@ -392,6 +406,8 @@ static int ov5647_sensor_power(struct v4l2_subdev *sd, int on)
                        dev_dbg(&client->dev, "soft stby failed\n");
 
                clk_disable_unprepare(ov5647->xclk);
+
+               gpiod_set_value(ov5647->pwdn, 1);
        }
 
        /* Update the power count. */
@@ -603,6 +619,10 @@ static int ov5647_probe(struct i2c_client *client)
                return -EINVAL;
        }
 
+       /* Request the power down GPIO asserted */
+       sensor->pwdn = devm_gpiod_get_optional(&client->dev, "pwdn",
+                                              GPIOD_OUT_HIGH);
+
        mutex_init(&sensor->lock);
 
        sd = &sensor->sd;
@@ -616,7 +636,15 @@ static int ov5647_probe(struct i2c_client *client)
        if (ret < 0)
                goto mutex_remove;
 
+       if (sensor->pwdn) {
+               gpiod_set_value(sensor->pwdn, 0);
+               msleep(PWDN_ACTIVE_DELAY_MS);
+       }
+
        ret = ov5647_detect(sd);
+
+       gpiod_set_value(sensor->pwdn, 1);
+
        if (ret < 0)
                goto error;