gc0308
struct gc0308 *gc0308 = to_gc0308(sd);
gc0308->mode.out_format = gc0308_formats[i].regval;
gc0308->mode.subsample = mode->subsample;
gc0308->mode.width = mode->width;
gc0308->mode.height = mode->height;
static int gc0308_set_resolution(struct gc0308 *gc0308, int *ret)
{GC0308_SUBSAMPLE, gc0308->mode.subsample},
{GC0308_CROP_WIN_HEIGHT, gc0308->mode.height},
{GC0308_CROP_WIN_WIDTH, gc0308->mode.width},
return cci_multi_reg_write(gc0308->regmap, resolution_regs,
static int gc0308_start_stream(struct gc0308 *gc0308)
ret = pm_runtime_resume_and_get(gc0308->dev);
cci_multi_reg_write(gc0308->regmap, sensor_default_regs,
cci_update_bits(gc0308->regmap, GC0308_OUT_FORMAT,
GENMASK(4, 0), gc0308->mode.out_format, &ret);
gc0308_set_resolution(gc0308, &ret);
dev_err(gc0308->dev, "failed to update registers: %d\n", ret);
ret = __v4l2_ctrl_handler_setup(&gc0308->hdl);
dev_err(gc0308->dev, "failed to setup controls\n");
if (gc0308->mbus_config & V4L2_MBUS_VSYNC_ACTIVE_LOW)
if (gc0308->mbus_config & V4L2_MBUS_HSYNC_ACTIVE_LOW)
ret = cci_write(gc0308->regmap, GC0308_SYNC_MODE, sync_mode, NULL);
pm_runtime_put_autosuspend(gc0308->dev);
static int gc0308_stop_stream(struct gc0308 *gc0308)
pm_runtime_put_autosuspend(gc0308->dev);
struct gc0308 *gc0308 = to_gc0308(sd);
ret = gc0308_start_stream(gc0308);
ret = gc0308_stop_stream(gc0308);
static int gc0308_bus_config(struct gc0308 *gc0308)
struct device *dev = gc0308->dev;
gc0308->mbus_config = bus_cfg.bus.parallel.flags;
static int gc0308_init_controls(struct gc0308 *gc0308)
v4l2_ctrl_handler_init(&gc0308->hdl, 11);
gc0308->hblank = v4l2_ctrl_new_std(&gc0308->hdl, &gc0308_ctrl_ops,
gc0308->vblank = v4l2_ctrl_new_std(&gc0308->hdl, &gc0308_ctrl_ops,
gc0308->hflip = v4l2_ctrl_new_std(&gc0308->hdl, &gc0308_ctrl_ops,
gc0308->vflip = v4l2_ctrl_new_std(&gc0308->hdl, &gc0308_ctrl_ops,
v4l2_ctrl_new_std(&gc0308->hdl, &gc0308_ctrl_ops, V4L2_CID_PIXEL_RATE,
v4l2_ctrl_new_std(&gc0308->hdl, &gc0308_ctrl_ops,
v4l2_ctrl_new_std_menu_items(&gc0308->hdl, &gc0308_ctrl_ops,
v4l2_ctrl_new_std_menu(&gc0308->hdl, &gc0308_ctrl_ops,
v4l2_ctrl_new_std_menu(&gc0308->hdl, &gc0308_ctrl_ops,
v4l2_ctrl_new_std_menu(&gc0308->hdl, &gc0308_ctrl_ops,
v4l2_ctrl_new_int_menu(&gc0308->hdl, &gc0308_ctrl_ops,
gc0308->sd.ctrl_handler = &gc0308->hdl;
if (gc0308->hdl.error) {
ret = gc0308->hdl.error;
v4l2_ctrl_handler_free(&gc0308->hdl);
v4l2_ctrl_cluster(2, &gc0308->hflip);
v4l2_ctrl_cluster(2, &gc0308->hblank);
struct gc0308 *gc0308;
gc0308 = devm_kzalloc(dev, sizeof(*gc0308), GFP_KERNEL);
if (!gc0308)
gc0308->dev = dev;
dev_set_drvdata(dev, gc0308);
ret = gc0308_bus_config(gc0308);
gc0308->clk = devm_clk_get_optional(dev, NULL);
if (IS_ERR(gc0308->clk))
return dev_err_probe(dev, PTR_ERR(gc0308->clk),
gc0308->vdd = devm_regulator_get(dev, "vdd28");
if (IS_ERR(gc0308->vdd))
return dev_err_probe(dev, PTR_ERR(gc0308->vdd),
gc0308->pwdn_gpio = devm_gpiod_get(dev, "powerdown", GPIOD_OUT_LOW);
if (IS_ERR(gc0308->pwdn_gpio))
return dev_err_probe(dev, PTR_ERR(gc0308->pwdn_gpio),
gc0308->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
if (IS_ERR(gc0308->reset_gpio))
return dev_err_probe(dev, PTR_ERR(gc0308->reset_gpio),
gc0308->regmap = devm_regmap_init_i2c(client, &gc0308_regmap_config);
if (IS_ERR(gc0308->regmap))
return dev_err_probe(dev, PTR_ERR(gc0308->regmap),
v4l2_i2c_subdev_init(&gc0308->sd, client, &gc0308_subdev_ops);
gc0308->sd.internal_ops = &gc0308_internal_ops;
gc0308->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
ret = gc0308_init_controls(gc0308);
gc0308->sd.state_lock = gc0308->hdl.lock;
gc0308->pad.flags = MEDIA_PAD_FL_SOURCE;
gc0308->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
ret = media_entity_pads_init(&gc0308->sd.entity, 1, &gc0308->pad);
ret = v4l2_subdev_init_finalize(&gc0308->sd);
if (gc0308->clk) {
clkrate = clk_get_rate(gc0308->clk);
ret = cci_read(gc0308->regmap, GC0308_CHIP_ID, ®val, NULL);
ret = v4l2_async_register_subdev(&gc0308->sd);
v4l2_subdev_cleanup(&gc0308->sd);
media_entity_cleanup(&gc0308->sd.entity);
v4l2_ctrl_handler_free(&gc0308->hdl);
struct gc0308 *gc0308 = i2c_get_clientdata(client);
v4l2_async_unregister_subdev(&gc0308->sd);
v4l2_ctrl_handler_free(&gc0308->hdl);
media_entity_cleanup(&gc0308->sd.entity);
static inline struct gc0308 *to_gc0308(struct v4l2_subdev *sd)
return container_of(sd, struct gc0308, sd);
struct gc0308 *gc0308 = dev_get_drvdata(dev);
ret = regulator_enable(gc0308->vdd);
ret = clk_prepare_enable(gc0308->clk);
gpiod_set_value_cansleep(gc0308->pwdn_gpio, 0);
gpiod_set_value_cansleep(gc0308->reset_gpio, 1);
gpiod_set_value_cansleep(gc0308->reset_gpio, 0);
regulator_disable(gc0308->vdd);
struct gc0308 *gc0308 = dev_get_drvdata(dev);
gpiod_set_value_cansleep(gc0308->pwdn_gpio, 1);
clk_disable_unprepare(gc0308->clk);
regulator_disable(gc0308->vdd);
struct gc0308 *gc0308 = to_gc0308(sd);
return cci_read(gc0308->regmap, CCI_REG8(reg->reg), ®->val, NULL);
struct gc0308 *gc0308 = to_gc0308(sd);
return cci_write(gc0308->regmap, CCI_REG8(reg->reg), reg->val, NULL);
static int gc0308_set_exposure(struct gc0308 *gc0308, enum gc0308_exp_val exp)
return cci_multi_reg_write(gc0308->regmap, exposure_reg_seq,
static int gc0308_set_awb_mode(struct gc0308 *gc0308,
ret = cci_update_bits(gc0308->regmap, GC0308_AAAA_EN,
ret = cci_multi_reg_write(gc0308->regmap, awb_reg_seq,
static int gc0308_set_colormode(struct gc0308 *gc0308, enum v4l2_colorfx mode)
return cci_multi_reg_write(gc0308->regmap, colormode_reg_seq,
static int gc0308_set_power_line_freq(struct gc0308 *gc0308, int frequency)
return cci_multi_reg_write(gc0308->regmap, pwr_line_60hz,
return cci_multi_reg_write(gc0308->regmap, pwr_line_50hz,
static int gc0308_update_mirror(struct gc0308 *gc0308)
if (gc0308->vflip->val)
if (gc0308->hflip->val)
return cci_update_bits(gc0308->regmap, GC0308_CISCTL_MODE1,
static int gc0308_update_blanking(struct gc0308 *gc0308)
u16 vblank = gc0308->vblank->val;
u16 hblank = gc0308->hblank->val;
cci_write(gc0308->regmap, GC0308_VB_HB, vbhb, &ret);
cci_write(gc0308->regmap, GC0308_HBLANK, hblank & 0xff, &ret);
cci_write(gc0308->regmap, GC0308_VBLANK, vblank & 0xff, &ret);
struct gc0308 *gc0308 = container_of(ctrl->handler, struct gc0308, hdl);
return gc0308_update_blanking(gc0308);
return gc0308_update_mirror(gc0308);
return cci_update_bits(gc0308->regmap, GC0308_AAAA_EN,
return gc0308_set_awb_mode(gc0308, ctrl->val);
return gc0308_set_power_line_freq(gc0308, ctrl->val);
return gc0308_set_colormode(gc0308, ctrl->val);
return cci_update_bits(gc0308->regmap, GC0308_DEBUG_MODE2,
return gc0308_set_exposure(gc0308, ctrl->val);
struct gc0308 *gc0308 = container_of(ctrl->handler, struct gc0308, hdl);
if (!pm_runtime_get_if_in_use(gc0308->dev))
dev_err(gc0308->dev, "failed to set control: %d\n", ret);
pm_runtime_put_autosuspend(gc0308->dev);