s5k3m5
struct s5k3m5 *s5k3m5 = to_s5k3m5(sd);
code->code = s5k3m5_get_format_code(s5k3m5);
struct s5k3m5 *s5k3m5 = to_s5k3m5(sd);
if (fse->code != s5k3m5_get_format_code(s5k3m5))
struct s5k3m5 *s5k3m5 = to_s5k3m5(sd);
sel->r.width = s5k3m5->mode->width;
sel->r.height = s5k3m5->mode->width;
struct s5k3m5 *s5k3m5 = to_s5k3m5(sd);
.width = s5k3m5->mode->width,
.height = s5k3m5->mode->height,
static int s5k3m5_identify_sensor(struct s5k3m5 *s5k3m5)
ret = cci_read(s5k3m5->regmap, S5K3M5_REG_CHIP_ID, &val, NULL);
dev_err(s5k3m5->dev, "failed to read chip id: %d\n", ret);
dev_err(s5k3m5->dev, "chip id mismatch: %x!=%llx\n",
static int s5k3m5_check_hwcfg(struct s5k3m5 *s5k3m5)
struct fwnode_handle *fwnode = dev_fwnode(s5k3m5->dev), *ep;
dev_err(s5k3m5->dev, "Invalid number of data lanes: %u\n",
ret = v4l2_link_freq_to_bitmap(s5k3m5->dev, bus_cfg.link_frequencies,
struct s5k3m5 *s5k3m5 = to_s5k3m5(sd);
ret = regulator_bulk_enable(S5K3M5_NUM_SUPPLIES, s5k3m5->supplies);
ret = clk_prepare_enable(s5k3m5->mclk);
gpiod_set_value_cansleep(s5k3m5->reset_gpio, 0);
regulator_bulk_disable(S5K3M5_NUM_SUPPLIES, s5k3m5->supplies);
struct s5k3m5 *s5k3m5 = to_s5k3m5(sd);
gpiod_set_value_cansleep(s5k3m5->reset_gpio, 1);
clk_disable_unprepare(s5k3m5->mclk);
regulator_bulk_disable(S5K3M5_NUM_SUPPLIES, s5k3m5->supplies);
struct s5k3m5 *s5k3m5;
s5k3m5 = devm_kzalloc(&client->dev, sizeof(*s5k3m5), GFP_KERNEL);
if (!s5k3m5)
s5k3m5->dev = &client->dev;
v4l2_i2c_subdev_init(&s5k3m5->sd, client, &s5k3m5_subdev_ops);
s5k3m5->regmap = devm_cci_regmap_init_i2c(client, 16);
if (IS_ERR(s5k3m5->regmap))
return dev_err_probe(s5k3m5->dev, PTR_ERR(s5k3m5->regmap),
s5k3m5->mclk = devm_v4l2_sensor_clk_get(s5k3m5->dev, NULL);
if (IS_ERR(s5k3m5->mclk))
return dev_err_probe(s5k3m5->dev, PTR_ERR(s5k3m5->mclk),
freq = clk_get_rate(s5k3m5->mclk);
return dev_err_probe(s5k3m5->dev, -EINVAL,
ret = s5k3m5_check_hwcfg(s5k3m5);
return dev_err_probe(s5k3m5->dev, ret,
s5k3m5->reset_gpio = devm_gpiod_get_optional(s5k3m5->dev, "reset",
if (IS_ERR(s5k3m5->reset_gpio))
return dev_err_probe(s5k3m5->dev, PTR_ERR(s5k3m5->reset_gpio),
s5k3m5->supplies[i].supply = s5k3m5_supply_names[i];
ret = devm_regulator_bulk_get(s5k3m5->dev, S5K3M5_NUM_SUPPLIES,
s5k3m5->supplies);
return dev_err_probe(s5k3m5->dev, ret,
ret = s5k3m5_power_on(s5k3m5->dev);
ret = s5k3m5_identify_sensor(s5k3m5);
dev_err_probe(s5k3m5->dev, ret, "failed to find sensor\n");
s5k3m5->mode = &s5k3m5_supported_modes[0];
ret = s5k3m5_init_controls(s5k3m5);
dev_err_probe(s5k3m5->dev, ret, "failed to init controls\n");
s5k3m5->sd.state_lock = s5k3m5->ctrl_handler.lock;
s5k3m5->sd.internal_ops = &s5k3m5_internal_ops;
s5k3m5->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
s5k3m5->sd.entity.ops = &s5k3m5_subdev_entity_ops;
s5k3m5->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
s5k3m5->pad.flags = MEDIA_PAD_FL_SOURCE;
ret = media_entity_pads_init(&s5k3m5->sd.entity, 1, &s5k3m5->pad);
dev_err_probe(s5k3m5->dev, ret,
ret = v4l2_subdev_init_finalize(&s5k3m5->sd);
dev_err_probe(s5k3m5->dev, ret,
pm_runtime_set_active(s5k3m5->dev);
pm_runtime_enable(s5k3m5->dev);
ret = v4l2_async_register_subdev_sensor(&s5k3m5->sd);
dev_err_probe(s5k3m5->dev, ret,
pm_runtime_set_autosuspend_delay(s5k3m5->dev, 1000);
pm_runtime_use_autosuspend(s5k3m5->dev);
pm_runtime_idle(s5k3m5->dev);
v4l2_subdev_cleanup(&s5k3m5->sd);
pm_runtime_disable(s5k3m5->dev);
pm_runtime_set_suspended(s5k3m5->dev);
media_entity_cleanup(&s5k3m5->sd.entity);
v4l2_ctrl_handler_free(s5k3m5->sd.ctrl_handler);
s5k3m5_power_off(s5k3m5->dev);
struct s5k3m5 *s5k3m5 = to_s5k3m5(sd);
pm_runtime_disable(s5k3m5->dev);
if (!pm_runtime_status_suspended(s5k3m5->dev)) {
s5k3m5_power_off(s5k3m5->dev);
pm_runtime_set_suspended(s5k3m5->dev);
#define to_s5k3m5(_sd) container_of(_sd, struct s5k3m5, sd)
struct s5k3m5 *s5k3m5 = container_of(ctrl->handler, struct s5k3m5,
const struct s5k3m5_mode *mode = s5k3m5->mode;
__v4l2_ctrl_modify_range(s5k3m5->exposure,
s5k3m5->exposure->minimum,
s5k3m5->exposure->step,
s5k3m5->exposure->default_value);
if (!pm_runtime_get_if_active(s5k3m5->dev))
ret = cci_write(s5k3m5->regmap, S5K3M5_REG_AGAIN,
ret = cci_write(s5k3m5->regmap, S5K3M5_REG_EXPOSURE,
ret = cci_write(s5k3m5->regmap, S5K3M5_REG_VTS,
ret = cci_write(s5k3m5->regmap, S5K3M5_REG_TEST_PATTERN,
pm_runtime_put(s5k3m5->dev);
static int s5k3m5_init_controls(struct s5k3m5 *s5k3m5)
struct v4l2_ctrl_handler *ctrl_hdlr = &s5k3m5->ctrl_handler;
const struct s5k3m5_mode *mode = s5k3m5->mode;
s5k3m5->link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr, &s5k3m5_ctrl_ops,
if (s5k3m5->link_freq)
s5k3m5->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
s5k3m5->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &s5k3m5_ctrl_ops,
s5k3m5->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &s5k3m5_ctrl_ops,
if (s5k3m5->hblank)
s5k3m5->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
s5k3m5->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &s5k3m5_ctrl_ops,
s5k3m5->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &s5k3m5_ctrl_ops,
s5k3m5->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &s5k3m5_ctrl_ops,
if (s5k3m5->hflip)
s5k3m5->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
s5k3m5->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &s5k3m5_ctrl_ops,
if (s5k3m5->vflip)
s5k3m5->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
ret = v4l2_fwnode_device_parse(s5k3m5->dev, &props);
s5k3m5->sd.ctrl_handler = ctrl_hdlr;
struct s5k3m5 *s5k3m5 = to_s5k3m5(sd);
const struct s5k3m5_reg_list *reg_list = &s5k3m5->mode->reg_list;
ret = pm_runtime_resume_and_get(s5k3m5->dev);
cci_write(s5k3m5->regmap, CCI_REG16(0x6028), 0x4000, &ret);
cci_write(s5k3m5->regmap, CCI_REG16(0x0000), 0x0006, &ret);
cci_write(s5k3m5->regmap, CCI_REG16(0x0000), S5K3M5_CHIP_ID, &ret);
cci_write(s5k3m5->regmap, CCI_REG16(0x6214), 0x7971, &ret);
cci_write(s5k3m5->regmap, CCI_REG16(0x6218), 0x7150, &ret);
cci_write(s5k3m5->regmap, CCI_REG16(0x0a02), 0x7800, &ret);
cci_write(s5k3m5->regmap, CCI_REG16(0x6028), 0x2000, &ret);
cci_write(s5k3m5->regmap, CCI_REG16(0x602a), 0x3eac, &ret);
cci_multi_reg_write(s5k3m5->regmap, burst_array_setting,
cci_multi_reg_write(s5k3m5->regmap, init_array_setting,
cci_multi_reg_write(s5k3m5->regmap, reg_list->regs,
ret = __v4l2_ctrl_handler_setup(s5k3m5->sd.ctrl_handler);
cci_write(s5k3m5->regmap, S5K3M5_REG_CTRL_MODE,
(s5k3m5->vflip->val ? S5K3M5_VFLIP : 0) |
(s5k3m5->hflip->val ? S5K3M5_HFLIP : 0), &ret);
dev_err(s5k3m5->dev, "failed to start streaming: %d\n", ret);
pm_runtime_put_autosuspend(s5k3m5->dev);
struct s5k3m5 *s5k3m5 = to_s5k3m5(sd);
ret = cci_write(s5k3m5->regmap, S5K3M5_REG_CTRL_MODE, 0, NULL);
dev_err(s5k3m5->dev, "failed to stop streaming: %d\n", ret);
pm_runtime_put_autosuspend(s5k3m5->dev);
static u32 s5k3m5_get_format_code(struct s5k3m5 *s5k3m5)
i = (s5k3m5->vflip->val ? 2 : 0) | (s5k3m5->hflip->val ? 1 : 0);
static void s5k3m5_update_pad_format(struct s5k3m5 *s5k3m5,
fmt->code = s5k3m5_get_format_code(s5k3m5);
struct s5k3m5 *s5k3m5 = to_s5k3m5(sd);
s5k3m5_update_pad_format(s5k3m5, mode, &fmt->format);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY || s5k3m5->mode == mode)
__v4l2_ctrl_modify_range(s5k3m5->hblank, hblank, hblank, 1, hblank);
__v4l2_ctrl_modify_range(s5k3m5->vblank, vblank,
__v4l2_ctrl_s_ctrl(s5k3m5->vblank, vblank);
__v4l2_ctrl_modify_range(s5k3m5->exposure, S5K3M5_EXPOSURE_MIN,
__v4l2_ctrl_s_ctrl(s5k3m5->exposure, mode->exposure);
if (s5k3m5->sd.ctrl_handler->error)
return s5k3m5->sd.ctrl_handler->error;
s5k3m5->mode = mode;