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

media: i2c: rdacm21: Power up OV10640 before OV490

The current RDACM21 initialization routine powers up the OV10640 image
sensor after the OV490 ISP. The ISP is programmed with a firmware loaded
from an embedded serial flash that (most probably) tries to interact and
program also the image sensor connected to the ISP.

As described in commit "media: i2c: rdacm21: Fix OV10640 powerup" the
image sensor powerdown signal is kept high by an internal pull up
resistor and occasionally fails to startup correctly if the powerdown
line is not asserted explicitly. Failures in the OV10640 startup causes
the OV490 firmware to fail to boot correctly resulting in the camera
module initialization to fail consequentially.

Fix this by powering up the OV10640 image sensor before testing the
OV490 firmware boot completion, by splitting the ov10640_initialize()
function in an ov10640_power_up() one and an ov10640_check_id() one.

Also make sure the OV10640 identification procedure gives enough time to
the image sensor to resume after the programming phase performed by the
OV490 firmware by repeating the ID read procedure.

This commit fixes a sporadic start-up error triggered by a failure to
detect the OV490 firmware boot completion:
rdacm21 8-0054: Timeout waiting for firmware boot

[hverkuil: fixed two typos in commit log]

Fixes: a59f853b3b4b ("media: i2c: Add driver for RDACM21 camera module")
Signed-off-by: Jacopo Mondi <jacopo+renesas@jmondi.org>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>

authored by

Jacopo Mondi and committed by
Mauro Carvalho Chehab
2b821698 ff75332b

+30 -12
+30 -12
drivers/media/i2c/rdacm21.c
··· 69 69 #define OV490_ISP_VSIZE_LOW 0x80820062 70 70 #define OV490_ISP_VSIZE_HIGH 0x80820063 71 71 72 + #define OV10640_PID_TIMEOUT 20 72 73 #define OV10640_ID_HIGH 0xa6 73 74 #define OV10640_CHIP_ID 0x300a 74 75 #define OV10640_PIXEL_RATE 55000000 ··· 330 329 .pad = &rdacm21_subdev_pad_ops, 331 330 }; 332 331 333 - static int ov10640_initialize(struct rdacm21_device *dev) 332 + static void ov10640_power_up(struct rdacm21_device *dev) 334 333 { 335 - u8 val; 336 - 337 334 /* Enable GPIO0#0 (reset) and GPIO1#0 (pwdn) as output lines. */ 338 335 ov490_write_reg(dev, OV490_GPIO_SEL0, OV490_GPIO0); 339 336 ov490_write_reg(dev, OV490_GPIO_SEL1, OV490_SPWDN0); ··· 346 347 usleep_range(1500, 3000); 347 348 ov490_write_reg(dev, OV490_GPIO_OUTPUT_VALUE0, OV490_GPIO0); 348 349 usleep_range(3000, 5000); 350 + } 351 + 352 + static int ov10640_check_id(struct rdacm21_device *dev) 353 + { 354 + unsigned int i; 355 + u8 val; 349 356 350 357 /* Read OV10640 ID to test communications. */ 351 - ov490_write_reg(dev, OV490_SCCB_SLAVE0_DIR, OV490_SCCB_SLAVE_READ); 352 - ov490_write_reg(dev, OV490_SCCB_SLAVE0_ADDR_HIGH, OV10640_CHIP_ID >> 8); 353 - ov490_write_reg(dev, OV490_SCCB_SLAVE0_ADDR_LOW, OV10640_CHIP_ID & 0xff); 358 + for (i = 0; i < OV10640_PID_TIMEOUT; ++i) { 359 + ov490_write_reg(dev, OV490_SCCB_SLAVE0_DIR, 360 + OV490_SCCB_SLAVE_READ); 361 + ov490_write_reg(dev, OV490_SCCB_SLAVE0_ADDR_HIGH, 362 + OV10640_CHIP_ID >> 8); 363 + ov490_write_reg(dev, OV490_SCCB_SLAVE0_ADDR_LOW, 364 + OV10640_CHIP_ID & 0xff); 354 365 355 - /* Trigger SCCB slave transaction and give it some time to complete. */ 356 - ov490_write_reg(dev, OV490_HOST_CMD, OV490_HOST_CMD_TRIGGER); 357 - usleep_range(1000, 1500); 366 + /* 367 + * Trigger SCCB slave transaction and give it some time 368 + * to complete. 369 + */ 370 + ov490_write_reg(dev, OV490_HOST_CMD, OV490_HOST_CMD_TRIGGER); 371 + usleep_range(1000, 1500); 358 372 359 - ov490_read_reg(dev, OV490_SCCB_SLAVE0_DIR, &val); 360 - if (val != OV10640_ID_HIGH) { 373 + ov490_read_reg(dev, OV490_SCCB_SLAVE0_DIR, &val); 374 + if (val == OV10640_ID_HIGH) 375 + break; 376 + usleep_range(1000, 1500); 377 + } 378 + if (i == OV10640_PID_TIMEOUT) { 361 379 dev_err(dev->dev, "OV10640 ID mismatch: (0x%02x)\n", val); 362 380 return -ENODEV; 363 381 } ··· 389 373 u8 pid, ver, val; 390 374 unsigned int i; 391 375 int ret; 376 + 377 + ov10640_power_up(dev); 392 378 393 379 /* 394 380 * Read OV490 Id to test communications. Give it up to 40msec to ··· 429 411 return -ENODEV; 430 412 } 431 413 432 - ret = ov10640_initialize(dev); 414 + ret = ov10640_check_id(dev); 433 415 if (ret) 434 416 return ret; 435 417