From e2409ffe9fca38c9a097070af5cefe3597a3b500 Mon Sep 17 00:00:00 2001 From: Vladimir Barinov Date: Fri, 25 Aug 2017 03:15:29 +0300 Subject: LVDS: fix camera start-up (stability work) Some cameras with OV10640/OV490 are bad in h/w and does not match start up sequence: PWDN/RESETB that lead to OV10640 hang. This patch fixes that in s/w. --- .../linux-renesas/0030-Gen3-LVDS-cameras.patch | 91 +++++++++++++++++++--- 1 file changed, 79 insertions(+), 12 deletions(-) diff --git a/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0030-Gen3-LVDS-cameras.patch b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0030-Gen3-LVDS-cameras.patch index 3e2138c..461b2c7 100644 --- a/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0030-Gen3-LVDS-cameras.patch +++ b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0030-Gen3-LVDS-cameras.patch @@ -11,13 +11,13 @@ Signed-off-by: Vladimir Barinov --- drivers/media/i2c/soc_camera/Kconfig | 47 + drivers/media/i2c/soc_camera/Makefile | 7 + - drivers/media/i2c/soc_camera/max9286_max9271.c | 566 +++++++++++ + drivers/media/i2c/soc_camera/max9286_max9271.c | 567 +++++++++++ drivers/media/i2c/soc_camera/max9286_max9271.h | 196 ++++ drivers/media/i2c/soc_camera/ov10635.c | 759 ++++++++++++++ drivers/media/i2c/soc_camera/ov10635.h | 1139 ++++++++++++++++++++++ drivers/media/i2c/soc_camera/ov10635_debug.h | 54 + drivers/media/i2c/soc_camera/ov106xx.c | 95 ++ - drivers/media/i2c/soc_camera/ov490_ov10640.c | 979 +++++++++++++++++++ + drivers/media/i2c/soc_camera/ov490_ov10640.c | 1046 ++++++++++++++++++++ drivers/media/i2c/soc_camera/ov490_ov10640.h | 88 ++ drivers/media/i2c/soc_camera/ov495_ov2775.c | 658 +++++++++++++ drivers/media/i2c/soc_camera/ov495_ov2775.h | 23 + @@ -30,7 +30,7 @@ Signed-off-by: Vladimir Barinov drivers/media/platform/soc_camera/soc_mediabus.c | 16 + include/media/drv-intf/soc_mediabus.h | 3 + include/media/soc_camera.h | 1 + - 21 files changed, 5905 insertions(+), 109 deletions(-) + 21 files changed, 5973 insertions(+), 109 deletions(-) create mode 100644 drivers/media/i2c/soc_camera/max9286_max9271.c create mode 100644 drivers/media/i2c/soc_camera/max9286_max9271.h create mode 100644 drivers/media/i2c/soc_camera/ov10635.c @@ -125,7 +125,7 @@ index 6f994f9..7d4c1ab 100644 obj-$(CONFIG_SOC_CAMERA_OV6650) += ov6650.o diff --git a/drivers/media/i2c/soc_camera/max9286_max9271.c b/drivers/media/i2c/soc_camera/max9286_max9271.c new file mode 100644 -index 0000000..a663a66 +index 0000000..9797d24 --- /dev/null +++ b/drivers/media/i2c/soc_camera/max9286_max9271.c @@ -0,0 +1,567 @@ @@ -215,7 +215,7 @@ index 0000000..a663a66 + reg8_write(client, 0x0f, (0xfe & ~BIT(priv->gpio_resetb)) | + (priv->active_low_resetb ? 0 : BIT(priv->gpio_resetb))); /* set GPIOn value to reset */ + reg8_write(client, 0x0e, 0x42 | BIT(priv->gpio_resetb)); /* set GPIOn direction output */ -+ mdelay(10); ++ usleep_range(2000, 2500); /* wait 2ms */ + reg8_write(client, 0x0f, (0xfe & ~BIT(priv->gpio_resetb)) | + (priv->active_low_resetb ? BIT(priv->gpio_resetb) : 0)); /* set GPIOn value to un-reset */ + usleep_range(2000, 2500); /* wait 2ms */ @@ -2971,10 +2971,10 @@ index 0000000..0079bb2 +MODULE_LICENSE("GPL"); diff --git a/drivers/media/i2c/soc_camera/ov490_ov10640.c b/drivers/media/i2c/soc_camera/ov490_ov10640.c new file mode 100644 -index 0000000..71cb68a +index 0000000..15acc51 --- /dev/null +++ b/drivers/media/i2c/soc_camera/ov490_ov10640.c -@@ -0,0 +1,979 @@ +@@ -0,0 +1,1046 @@ +/* + * OmniVision ov490-ov10640 sensor camera driver + * @@ -3034,8 +3034,8 @@ index 0000000..71cb68a + int ti9x3_addr; + int port; + int gpio_resetb; ++ int active_low_resetb; + int gpio_fsin; -+ +}; + +static int force_conf_link; @@ -3068,6 +3068,48 @@ index 0000000..71cb68a + }; +} + ++static void ov490_reset(struct i2c_client *client) ++{ ++ struct ov490_priv *priv = to_ov490(client); ++ int tmp_addr; ++ ++ if (priv->max9286_addr) { ++ if (priv->gpio_resetb < 1 || priv->gpio_resetb > 5) ++ return; ++ ++ tmp_addr = client->addr; ++ /* get out from sensor reset */ ++ client->addr = priv->max9271_addr; /* MAX9271 I2C address */ ++ reg8_write(client, 0x0f, (0xfe & ~BIT(priv->gpio_resetb)) | ++ (priv->active_low_resetb ? 0 : BIT(priv->gpio_resetb))); /* set GPIOn value to reset */ ++ usleep_range(2000, 2500); /* wait 2ms */ ++ reg8_write(client, 0x0f, (0xfe & ~BIT(priv->gpio_resetb)) | ++ (priv->active_low_resetb ? BIT(priv->gpio_resetb) : 0)); /* set GPIOn value to un-reset */ ++ usleep_range(2000, 2500); /* wait 2ms */ ++ client->addr = tmp_addr; ++ } ++ ++ if (priv->ti964_addr) { ++ client->addr = priv->ti964_addr; /* TI964 I2C address */ ++ ++ reg8_write(client, 0x4c, (priv->port << 4) | (1 << priv->port)); /* Select RX port number */ ++ usleep_range(2000, 2500); /* wait 2ms */ ++ reg8_write(client, 0x6e, 0x8a); /* set GPIO1 value to reset */ ++ usleep_range(2000, 2500); /* wait 2ms */ ++ reg8_write(client, 0x6e, 0x9a); /* set GPIO1 value to un-reset */ ++ } ++ ++ if (priv->ti954_addr) { ++ client->addr = priv->ti954_addr; /* TI964 I2C address */ ++ ++ reg8_write(client, 0x4c, (priv->port << 4) | (1 << priv->port)); /* Select RX port number */ ++ usleep_range(2000, 2500); /* wait 2ms */ ++ reg8_write(client, 0x6e, 0x8a); /* set GPIO1 value to reset */ ++ usleep_range(2000, 2500); /* wait 2ms */ ++ reg8_write(client, 0x6e, 0x9a); /* set GPIO1 value to un-reset */ ++ } ++} ++ +static int ov490_set_regs(struct i2c_client *client, + const struct ov490_reg *regs, int nr_regs) +{ @@ -3646,7 +3688,7 @@ index 0000000..71cb68a + struct ov490_priv *priv = to_ov490(client); + u8 val = 0; + u8 pid = 0, ver = 0; -+ int ret = 0, timeout = 1000; ++ int ret = 0, timeout, retry_timeout = 3; + + if (priv->is_fixed_sensor) { + dev_info(&client->dev, "ov490/ov10640 fixed-sensor res %dx%d\n", priv->max_width, priv->max_height); @@ -3671,10 +3713,12 @@ index 0000000..71cb68a + if (unlikely(force_conf_link)) + goto out; + ++again: + /* Check if firmware booted by reading stream-on status */ + reg16_write(client, 0xFFFD, 0x80); + reg16_write(client, 0xFFFE, 0x29); + usleep_range(100, 150); /* wait 100 us */ ++ timeout = 300; + for (;;) { + reg16_read(client, 0xd000, &val); + if (val == 0x0c || --timeout == 0) @@ -3682,8 +3726,22 @@ index 0000000..71cb68a + mdelay(1); + } + -+ if (!timeout) -+ dev_err(&client->dev, "Timeout firmware boot wait\n"); ++ if (!timeout) { ++ dev_err(&client->dev, "Timeout firmware boot wait, retrying\n"); ++ /* reset OV10640 using RESETB pin controlled by OV490 GPIO0 */ ++ reg16_write(client, 0xFFFD, 0x80); ++ reg16_write(client, 0xFFFE, 0x80); ++ usleep_range(100, 150); /* wait 100 us */ ++ reg16_write(client, 0x0050, 0x01); ++ reg16_write(client, 0x0054, 0x01); ++ reg16_write(client, 0x0058, 0x00); ++ mdelay(10); ++ reg16_write(client, 0x0058, 0x01); ++ /* reset OV490 using RESETB pin controlled by serializer */ ++ ov490_reset(client); ++ if (retry_timeout--) ++ goto again; ++ } + + /* read resolution used by current firmware */ + reg16_write(client, 0xFFFD, 0x80); @@ -3739,8 +3797,17 @@ index 0000000..71cb68a + + if (!of_property_read_u32(rendpoint, "max9271-addr", &priv->max9271_addr) && + !of_property_read_u32(rendpoint->parent->parent, "reg", &priv->max9286_addr) && -+ !kstrtouint(strrchr(rendpoint->full_name, '@') + 1, 0, &priv->port)) ++ !kstrtouint(strrchr(rendpoint->full_name, '@') + 1, 0, &priv->port)) { ++ if (of_property_read_u32(rendpoint->parent->parent, "maxim,resetb-gpio", &priv->gpio_resetb)) { ++ priv->gpio_resetb = -1; ++ } else { ++ if (of_property_read_bool(rendpoint->parent->parent, "maxim,resetb-active-high")) ++ priv->active_low_resetb = false; ++ else ++ priv->active_low_resetb = true; ++ } + break; ++ } + + if (!of_property_read_u32(rendpoint, "ti9x3-addr", &priv->ti9x3_addr) && + !of_property_match_string(rendpoint->parent->parent, "compatible", "ti,ti964-ti9x3") && -- cgit 1.2.3-korg