ov02c10
static inline struct ov02c10 *to_ov02c10(struct v4l2_subdev *subdev)
return container_of(subdev, struct ov02c10, sd);
static int ov02c10_test_pattern(struct ov02c10 *ov02c10, int pattern)
return cci_update_bits(ov02c10->regmap, OV02C10_REG_TEST_PATTERN,
cci_update_bits(ov02c10->regmap, OV02C10_REG_TEST_PATTERN,
cci_update_bits(ov02c10->regmap, OV02C10_REG_TEST_PATTERN,
struct ov02c10 *ov02c10 = container_of(ctrl->handler,
struct ov02c10, ctrl_handler);
__v4l2_ctrl_modify_range(ov02c10->exposure,
ov02c10->exposure->minimum,
exposure_max, ov02c10->exposure->step,
if (!pm_runtime_get_if_in_use(ov02c10->dev))
cci_write(ov02c10->regmap, OV02C10_REG_ANALOG_GAIN,
cci_write(ov02c10->regmap, OV02C10_REG_DIGITAL_GAIN,
cci_write(ov02c10->regmap, OV02C10_REG_EXPOSURE,
cci_write(ov02c10->regmap, OV02C10_REG_VTS, height + ctrl->val,
ret = ov02c10_test_pattern(ov02c10, ctrl->val);
cci_write(ov02c10->regmap, OV02C10_ISP_X_WIN_CONTROL,
cci_update_bits(ov02c10->regmap, OV02C10_ROTATE_CONTROL,
cci_write(ov02c10->regmap, OV02C10_ISP_Y_WIN_CONTROL,
cci_update_bits(ov02c10->regmap, OV02C10_ROTATE_CONTROL,
pm_runtime_put(ov02c10->dev);
static int ov02c10_init_controls(struct ov02c10 *ov02c10)
struct v4l2_ctrl_handler *ctrl_hdlr = &ov02c10->ctrl_handler;
ov02c10->link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr,
ov02c10->link_freq_index, 0,
if (ov02c10->link_freq)
ov02c10->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
pixel_rate = div_u64(link_freq_menu_items[ov02c10->link_freq_index] *
2 * ov02c10->mipi_lanes, OV02C10_RGB_DEPTH);
ov02c10->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &ov02c10_ctrl_ops,
vts_def = mode->vts_min * ov02c10->mipi_lanes;
ov02c10->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &ov02c10_ctrl_ops,
ov02c10->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &ov02c10_ctrl_ops,
if (ov02c10->hblank)
ov02c10->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
ov02c10->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &ov02c10_ctrl_ops,
ret = v4l2_fwnode_device_parse(ov02c10->dev, &props);
ov02c10->sd.ctrl_handler = ctrl_hdlr;
struct ov02c10 *ov02c10 = to_ov02c10(sd);
ret = pm_runtime_resume_and_get(ov02c10->dev);
ret = regmap_multi_reg_write(ov02c10->regmap,
dev_err(ov02c10->dev, "failed to set mode\n");
reg_sequence = mode->lane_settings[ov02c10->mipi_lanes - 1];
sequence_length = mode->lane_settings_length[ov02c10->mipi_lanes - 1];
ret = regmap_multi_reg_write(ov02c10->regmap,
dev_err(ov02c10->dev, "failed to write lane settings\n");
ret = __v4l2_ctrl_handler_setup(ov02c10->sd.ctrl_handler);
ret = cci_write(ov02c10->regmap, OV02C10_REG_STREAM_CONTROL, 1, NULL);
pm_runtime_put(ov02c10->dev);
struct ov02c10 *ov02c10 = to_ov02c10(sd);
cci_write(ov02c10->regmap, OV02C10_REG_STREAM_CONTROL, 0, NULL);
pm_runtime_put(ov02c10->dev);
struct ov02c10 *ov02c10 = to_ov02c10(sd);
ov02c10->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
if (IS_ERR(ov02c10->reset))
return dev_err_probe(dev, PTR_ERR(ov02c10->reset),
ov02c10->supplies[i].supply = ov02c10_supply_names[i];
ov02c10->supplies);
struct ov02c10 *ov02c10 = to_ov02c10(sd);
gpiod_set_value_cansleep(ov02c10->reset, 1);
ov02c10->supplies);
clk_disable_unprepare(ov02c10->img_clk);
struct ov02c10 *ov02c10 = to_ov02c10(sd);
ret = clk_prepare_enable(ov02c10->img_clk);
ov02c10->supplies);
clk_disable_unprepare(ov02c10->img_clk);
if (ov02c10->reset) {
gpiod_set_value_cansleep(ov02c10->reset, 0);
struct ov02c10 *ov02c10 = to_ov02c10(sd);
vblank_def = mode->vts_min * ov02c10->mipi_lanes - mode->height;
__v4l2_ctrl_modify_range(ov02c10->vblank, mode->vts_min - mode->height,
__v4l2_ctrl_s_ctrl(ov02c10->vblank, vblank_def);
__v4l2_ctrl_modify_range(ov02c10->hblank, h_blank, h_blank, 1, h_blank);
static int ov02c10_identify_module(struct ov02c10 *ov02c10)
ret = cci_read(ov02c10->regmap, OV02C10_REG_CHIP_ID, &chip_id, NULL);
dev_err(ov02c10->dev, "chip id mismatch: %x!=%llx",
static int ov02c10_check_hwcfg(struct ov02c10 *ov02c10)
struct device *dev = ov02c10->dev;
ov02c10->link_freq_index = ffs(link_freq_bitmap) - 1;
ov02c10->mipi_lanes = bus_cfg.bus.mipi_csi2.num_data_lanes;
struct ov02c10 *ov02c10 = to_ov02c10(sd);
pm_runtime_disable(ov02c10->dev);
if (!pm_runtime_status_suspended(ov02c10->dev)) {
ov02c10_power_off(ov02c10->dev);
pm_runtime_set_suspended(ov02c10->dev);
struct ov02c10 *ov02c10;
ov02c10 = devm_kzalloc(&client->dev, sizeof(*ov02c10), GFP_KERNEL);
if (!ov02c10)
ov02c10->dev = &client->dev;
ov02c10->img_clk = devm_v4l2_sensor_clk_get(ov02c10->dev, NULL);
if (IS_ERR(ov02c10->img_clk))
return dev_err_probe(ov02c10->dev, PTR_ERR(ov02c10->img_clk),
freq = clk_get_rate(ov02c10->img_clk);
return dev_err_probe(ov02c10->dev, -EINVAL,
v4l2_i2c_subdev_init(&ov02c10->sd, client, &ov02c10_subdev_ops);
ret = ov02c10_check_hwcfg(ov02c10);
ret = ov02c10_get_pm_resources(ov02c10->dev);
ov02c10->regmap = devm_cci_regmap_init_i2c(client, 16);
if (IS_ERR(ov02c10->regmap))
return PTR_ERR(ov02c10->regmap);
ret = ov02c10_power_on(ov02c10->dev);
dev_err_probe(ov02c10->dev, ret, "failed to power on\n");
ret = ov02c10_identify_module(ov02c10);
dev_err(ov02c10->dev, "failed to find sensor: %d", ret);
ret = ov02c10_init_controls(ov02c10);
dev_err(ov02c10->dev, "failed to init controls: %d", ret);
ov02c10->sd.internal_ops = &ov02c10_internal_ops;
ov02c10->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
ov02c10->sd.entity.ops = &ov02c10_subdev_entity_ops;
ov02c10->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
ov02c10->pad.flags = MEDIA_PAD_FL_SOURCE;
ret = media_entity_pads_init(&ov02c10->sd.entity, 1, &ov02c10->pad);
dev_err(ov02c10->dev, "failed to init entity pads: %d", ret);
ov02c10->sd.state_lock = ov02c10->ctrl_handler.lock;
ret = v4l2_subdev_init_finalize(&ov02c10->sd);
dev_err(ov02c10->dev, "failed to init subdev: %d", ret);
pm_runtime_set_active(ov02c10->dev);
pm_runtime_enable(ov02c10->dev);
ret = v4l2_async_register_subdev_sensor(&ov02c10->sd);
dev_err(ov02c10->dev, "failed to register V4L2 subdev: %d",
pm_runtime_idle(ov02c10->dev);
pm_runtime_disable(ov02c10->dev);
pm_runtime_set_suspended(ov02c10->dev);
v4l2_subdev_cleanup(&ov02c10->sd);
media_entity_cleanup(&ov02c10->sd.entity);
v4l2_ctrl_handler_free(ov02c10->sd.ctrl_handler);
ov02c10_power_off(ov02c10->dev);