/* * Enable serial link now that the ISP provides a valid pixel clock * to start serializing video data on the GMSL link.
*/ return max9271_set_serial_link(&dev->serializer, enable);
}
/* Read OV10640 ID to test communications. */ for (i = 0; i < OV10640_PID_TIMEOUT; ++i) {
ov490_write_reg(dev, OV490_SCCB_SLAVE0_DIR,
OV490_SCCB_SLAVE_READ);
ov490_write_reg(dev, OV490_SCCB_SLAVE0_ADDR_HIGH,
OV10640_CHIP_ID >> 8);
ov490_write_reg(dev, OV490_SCCB_SLAVE0_ADDR_LOW,
OV10640_CHIP_ID & 0xff);
/* * Trigger SCCB slave transaction and give it some time * to complete.
*/
ov490_write_reg(dev, OV490_HOST_CMD, OV490_HOST_CMD_TRIGGER);
usleep_range(1000, 1500);
ov490_read_reg(dev, OV490_SCCB_SLAVE0_DIR, &val); if (val == OV10640_ID_HIGH) break;
usleep_range(1000, 1500);
} if (i == OV10640_PID_TIMEOUT) {
dev_err(dev->dev, "OV10640 ID mismatch: (0x%02x)\n", val); return -ENODEV;
}
/* * Read OV490 Id to test communications. Give it up to 40msec to * exit from reset.
*/ for (i = 0; i < OV490_PID_TIMEOUT; ++i) {
ret = ov490_read_reg(dev, OV490_PID, &pid); if (ret == 0) break;
usleep_range(1000, 2000);
} if (i == OV490_PID_TIMEOUT) {
dev_err(dev->dev, "OV490 PID read failed (%d)\n", ret); return ret;
}
ret = ov490_read_reg(dev, OV490_VER, &ver); if (ret < 0) return ret;
if (OV490_ID(pid, ver) != OV490_ID_VAL) {
dev_err(dev->dev, "OV490 ID mismatch (0x%04x)\n",
OV490_ID(pid, ver)); return -ENODEV;
}
/* Wait for firmware boot by reading streamon status. */ for (i = 0; i < OV490_OUTPUT_EN_TIMEOUT; ++i) {
ov490_read_reg(dev, OV490_ODS_CTRL, &val); if (val == OV490_ODS_CTRL_FRAME_OUTPUT_EN) break;
usleep_range(1000, 2000);
} if (i == OV490_OUTPUT_EN_TIMEOUT) {
dev_err(dev->dev, "Timeout waiting for firmware boot\n"); return -ENODEV;
}
ret = ov10640_check_id(dev); if (ret) return ret;
/* Program OV490 with register-value table. */ for (i = 0; i < ARRAY_SIZE(ov490_regs_wizard); ++i) {
ret = ov490_write(dev, ov490_regs_wizard[i].reg,
ov490_regs_wizard[i].val); if (ret < 0) {
dev_err(dev->dev, "%s: register %u (0x%04x) write failed (%d)\n",
__func__, i, ov490_regs_wizard[i].reg, ret);
return -EIO;
}
usleep_range(100, 150);
}
/* * The ISP is programmed with the content of a serial flash memory. * Read the firmware configuration to reflect it through the V4L2 APIs.
*/
ov490_read_reg(dev, OV490_ISP_HSIZE_HIGH, &val);
dev->fmt.width = (val & 0xf) << 8;
ov490_read_reg(dev, OV490_ISP_HSIZE_LOW, &val);
dev->fmt.width |= (val & 0xff);
/* Set bus width to 12 bits with [0:11] ordering. */
ov490_write_reg(dev, OV490_DVP_CTRL3, 0x10);
dev_info(dev->dev, "Identified RDACM21 camera module\n");
return 0;
}
staticint rdacm21_initialize(struct rdacm21_device *dev)
{ int ret;
max9271_wake_up(&dev->serializer);
/* Enable reverse channel and disable the serial link. */
ret = max9271_set_serial_link(&dev->serializer, false); if (ret) return ret;
/* Configure I2C bus at 105Kbps speed and configure GMSL. */
ret = max9271_configure_i2c(&dev->serializer,
MAX9271_I2CSLVSH_469NS_234NS |
MAX9271_I2CSLVTO_1024US |
MAX9271_I2CMSTBT_105KBPS); if (ret) return ret;
ret = max9271_verify_id(&dev->serializer); if (ret) return ret;
/* * Enable GPIO1 and hold OV490 in reset during max9271 configuration. * The reset signal has to be asserted for at least 250 useconds.
*/
ret = max9271_enable_gpios(&dev->serializer, MAX9271_GPIO1OUT); if (ret) return ret;
ret = max9271_clear_gpios(&dev->serializer, MAX9271_GPIO1OUT); if (ret) return ret;
usleep_range(250, 500);
ret = max9271_configure_gmsl_link(&dev->serializer); if (ret) return ret;
ret = max9271_set_address(&dev->serializer, dev->addrs[0]); if (ret) return ret;
dev->serializer.client->addr = dev->addrs[0];
ret = max9271_set_translation(&dev->serializer, dev->addrs[1],
OV490_I2C_ADDRESS); if (ret) return ret;
dev->isp->addr = dev->addrs[1];
/* Release OV490 from reset and initialize it. */
ret = max9271_set_gpios(&dev->serializer, MAX9271_GPIO1OUT); if (ret) return ret;
usleep_range(3000, 5000);
ret = ov490_initialize(dev); if (ret) return ret;
/* * Set reverse channel high threshold to increase noise immunity. * * This should be compensated by increasing the reverse channel * amplitude on the remote deserializer side.
*/ return max9271_set_high_threshold(&dev->serializer, true);
}
staticint rdacm21_probe(struct i2c_client *client)
{ struct rdacm21_device *dev; int ret;
dev = devm_kzalloc(&client->dev, sizeof(*dev), GFP_KERNEL); if (!dev) return -ENOMEM;
dev->dev = &client->dev;
dev->serializer.client = client;
/* Create the dummy I2C client for the sensor. */
dev->isp = i2c_new_dummy_device(client->adapter, OV490_I2C_ADDRESS); if (IS_ERR(dev->isp)) return PTR_ERR(dev->isp);
ret = rdacm21_initialize(dev); if (ret < 0) goto error;
/* Initialize and register the subdevice. */
v4l2_i2c_subdev_init(&dev->sd, client, &rdacm21_subdev_ops);
dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.