gc08a3
static void gc05a2_update_pad_format(struct gc05a2 *gc08a3,
static int gc08a3_get_regulators(struct device *dev, struct gc08a3 *gc08a3)
gc08a3->supplies[i].supply = gc08a3_supply_name[i];
gc08a3->supplies);
static int gc08a3_parse_fwnode(struct gc08a3 *gc08a3)
struct device *dev = gc08a3->dev;
&gc08a3->link_freq_bitmap);
static int gc08a3_init_controls(struct gc08a3 *gc08a3)
struct i2c_client *client = v4l2_get_subdevdata(&gc08a3->sd);
ctrl_hdlr = &gc08a3->ctrls;
gc08a3->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &gc08a3_ctrl_ops,
gc08a3->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &gc08a3_ctrl_ops,
v4l2_ctrl_cluster(2, &gc08a3->hflip);
gc08a3->link_freq =
if (gc08a3->link_freq)
gc08a3->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
gc08a3->pixel_rate =
gc08a3->vblank =
gc08a3->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &gc08a3_ctrl_ops,
if (gc08a3->hblank)
gc08a3->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
gc08a3->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &gc08a3_ctrl_ops,
gc08a3->sd.ctrl_handler = ctrl_hdlr;
static int gc08a3_identify_module(struct gc08a3 *gc08a3)
ret = cci_read(gc08a3->regmap, GC08A3_REG_CHIP_ID, &val, NULL);
dev_err(gc08a3->dev, "failed to read chip id");
dev_err(gc08a3->dev, "chip id mismatch: 0x%x!=0x%llx",
struct gc08a3 *gc08a3;
gc08a3 = devm_kzalloc(dev, sizeof(*gc08a3), GFP_KERNEL);
if (!gc08a3)
gc08a3->dev = dev;
ret = gc08a3_parse_fwnode(gc08a3);
gc08a3->regmap = devm_cci_regmap_init_i2c(client, 16);
if (IS_ERR(gc08a3->regmap))
return dev_err_probe(dev, PTR_ERR(gc08a3->regmap),
gc08a3->xclk = devm_v4l2_sensor_clk_get_legacy(dev, NULL, true,
if (IS_ERR(gc08a3->xclk))
return dev_err_probe(dev, PTR_ERR(gc08a3->xclk),
ret = gc08a3_get_regulators(dev, gc08a3);
gc08a3->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
if (IS_ERR(gc08a3->reset_gpio))
return dev_err_probe(dev, PTR_ERR(gc08a3->reset_gpio),
v4l2_i2c_subdev_init(&gc08a3->sd, client, &gc08a3_subdev_ops);
gc08a3->sd.internal_ops = &gc08a3_internal_ops;
gc08a3->cur_mode = &gc08a3_modes[0];
ret = gc08a3_power_on(gc08a3->dev);
ret = gc08a3_identify_module(gc08a3);
ret = gc08a3_init_controls(gc08a3);
gc08a3->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
gc08a3->pad.flags = MEDIA_PAD_FL_SOURCE;
gc08a3->sd.dev = &client->dev;
gc08a3->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
ret = media_entity_pads_init(&gc08a3->sd.entity, 1, &gc08a3->pad);
gc08a3->sd.state_lock = gc08a3->ctrls.lock;
ret = v4l2_subdev_init_finalize(&gc08a3->sd);
pm_runtime_set_active(gc08a3->dev);
pm_runtime_enable(gc08a3->dev);
pm_runtime_set_autosuspend_delay(gc08a3->dev, 1000);
pm_runtime_use_autosuspend(gc08a3->dev);
pm_runtime_idle(gc08a3->dev);
ret = v4l2_async_register_subdev_sensor(&gc08a3->sd);
pm_runtime_disable(gc08a3->dev);
v4l2_subdev_cleanup(&gc08a3->sd);
media_entity_cleanup(&gc08a3->sd.entity);
v4l2_ctrl_handler_free(gc08a3->sd.ctrl_handler);
gc08a3_power_off(gc08a3->dev);
struct gc08a3 *gc08a3 = to_gc08a3(sd);
v4l2_async_unregister_subdev(&gc08a3->sd);
media_entity_cleanup(&gc08a3->sd.entity);
v4l2_ctrl_handler_free(&gc08a3->ctrls);
gc08a3_power_off(gc08a3->dev);
static inline struct gc08a3 *to_gc08a3(struct v4l2_subdev *sd)
return container_of(sd, struct gc08a3, sd);
struct gc08a3 *gc08a3 = to_gc08a3(sd);
gc08a3->supplies);
dev_err(gc08a3->dev, "failed to enable regulators: %d\n", ret);
ret = clk_prepare_enable(gc08a3->xclk);
gc08a3->supplies);
dev_err(gc08a3->dev, "clk prepare enable failed\n");
gpiod_set_value_cansleep(gc08a3->reset_gpio, 0);
struct gc08a3 *gc08a3 = to_gc08a3(sd);
clk_disable_unprepare(gc08a3->xclk);
gpiod_set_value_cansleep(gc08a3->reset_gpio, 1);
gc08a3->supplies);
static int gc08a3_update_cur_mode_controls(struct gc08a3 *gc08a3,
ret = __v4l2_ctrl_modify_range(gc08a3->vblank,
dev_err(gc08a3->dev, "VB ctrl range update failed\n");
ret = __v4l2_ctrl_modify_range(gc08a3->hblank, h_blank, h_blank, 1,
dev_err(gc08a3->dev, "HB ctrl range update failed\n");
ret = __v4l2_ctrl_modify_range(gc08a3->exposure, GC08A3_EXP_MIN,
dev_err(gc08a3->dev, "exposure ctrl range update failed\n");
static void gc08a3_update_pad_format(struct gc08a3 *gc08a3,
struct gc08a3 *gc08a3 = to_gc08a3(sd);
gc08a3_update_pad_format(gc08a3, mode, &fmt->format);
gc08a3->cur_mode = mode;
gc08a3_update_cur_mode_controls(gc08a3, mode);
static int gc08a3_set_ctrl_hflip(struct gc08a3 *gc08a3, u32 ctrl_val)
ret = cci_read(gc08a3->regmap, GC08A3_FLIP_REG, &val, NULL);
dev_err(gc08a3->dev, "read hflip register failed: %d\n", ret);
return cci_update_bits(gc08a3->regmap, GC08A3_FLIP_REG,
static int gc08a3_set_ctrl_vflip(struct gc08a3 *gc08a3, u32 ctrl_val)
ret = cci_read(gc08a3->regmap, GC08A3_FLIP_REG, &val, NULL);
dev_err(gc08a3->dev, "read vflip register failed: %d\n", ret);
return cci_update_bits(gc08a3->regmap, GC08A3_FLIP_REG,
static int gc08a3_test_pattern(struct gc08a3 *gc08a3, u32 pattern_menu)
ret = cci_write(gc08a3->regmap, GC08A3_REG_TEST_PATTERN_IDX,
return cci_write(gc08a3->regmap, GC08A3_REG_TEST_PATTERN_EN,
return cci_write(gc08a3->regmap, GC08A3_REG_TEST_PATTERN_EN,
struct gc08a3 *gc08a3 =
container_of(ctrl->handler, struct gc08a3, ctrls);
state = v4l2_subdev_get_locked_active_state(&gc08a3->sd);
__v4l2_ctrl_modify_range(gc08a3->exposure,
gc08a3->exposure->minimum,
exposure_max, gc08a3->exposure->step,
if (!pm_runtime_get_if_active(gc08a3->dev))
ret = cci_write(gc08a3->regmap, GC08A3_EXP_REG,
ret = cci_write(gc08a3->regmap, GC08A3_AGAIN_REG,
ret = cci_write(gc08a3->regmap, GC08A3_FRAME_LENGTH_REG,
gc08a3->cur_mode->height + ctrl->val, NULL);
ret = gc08a3_set_ctrl_hflip(gc08a3, ctrl->val);
ret = gc08a3_set_ctrl_vflip(gc08a3, ctrl->val);
ret = gc08a3_test_pattern(gc08a3, ctrl->val);
pm_runtime_put(gc08a3->dev);
static int gc08a3_start_streaming(struct gc08a3 *gc08a3)
ret = pm_runtime_resume_and_get(gc08a3->dev);
ret = cci_multi_reg_write(gc08a3->regmap,
mode = gc08a3->cur_mode;
ret = cci_multi_reg_write(gc08a3->regmap,
ret = __v4l2_ctrl_handler_setup(&gc08a3->ctrls);
dev_err(gc08a3->dev, "could not sync v4l2 controls\n");
ret = cci_write(gc08a3->regmap, GC08A3_STREAMING_REG, 1, NULL);
dev_err(gc08a3->dev, "write STREAMING_REG failed: %d\n", ret);
pm_runtime_put(gc08a3->dev);
static int gc08a3_stop_streaming(struct gc08a3 *gc08a3)
ret = cci_write(gc08a3->regmap, GC08A3_STREAMING_REG, 0, NULL);
dev_err(gc08a3->dev, "could not sent stop streaming %d\n", ret);
pm_runtime_put(gc08a3->dev);
struct gc08a3 *gc08a3 = to_gc08a3(subdev);
ret = gc08a3_start_streaming(gc08a3);
ret = gc08a3_stop_streaming(gc08a3);