imx412
struct imx412 *imx412 = to_imx412(sd);
imx412->supplies);
gpiod_set_value_cansleep(imx412->reset_gpio, 0);
ret = clk_prepare_enable(imx412->inclk);
dev_err(imx412->dev, "fail to enable inclk\n");
gpiod_set_value_cansleep(imx412->reset_gpio, 1);
imx412->supplies);
struct imx412 *imx412 = to_imx412(sd);
clk_disable_unprepare(imx412->inclk);
gpiod_set_value_cansleep(imx412->reset_gpio, 1);
imx412->supplies);
static int imx412_init_controls(struct imx412 *imx412)
struct v4l2_ctrl_handler *ctrl_hdlr = &imx412->ctrl_handler;
const struct imx412_mode *mode = imx412->cur_mode;
ctrl_hdlr->lock = &imx412->mutex;
imx412->exp_ctrl = v4l2_ctrl_new_std(ctrl_hdlr,
imx412->again_ctrl = v4l2_ctrl_new_std(ctrl_hdlr,
v4l2_ctrl_cluster(2, &imx412->exp_ctrl);
imx412->vblank_ctrl = v4l2_ctrl_new_std(ctrl_hdlr,
imx412->pclk_ctrl = v4l2_ctrl_new_std(ctrl_hdlr,
imx412->link_freq_ctrl = v4l2_ctrl_new_int_menu(ctrl_hdlr,
if (imx412->link_freq_ctrl)
imx412->link_freq_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
imx412->hblank_ctrl = v4l2_ctrl_new_std(ctrl_hdlr,
if (imx412->hblank_ctrl)
imx412->hblank_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
dev_err(imx412->dev, "control init failed: %d\n",
imx412->sd.ctrl_handler = ctrl_hdlr;
struct imx412 *imx412;
imx412 = devm_kzalloc(&client->dev, sizeof(*imx412), GFP_KERNEL);
if (!imx412)
imx412->dev = &client->dev;
v4l2_i2c_subdev_init(&imx412->sd, client, &imx412_subdev_ops);
imx412->sd.internal_ops = &imx412_internal_ops;
ret = imx412_parse_hw_config(imx412);
dev_err(imx412->dev, "HW configuration is not supported\n");
mutex_init(&imx412->mutex);
ret = imx412_power_on(imx412->dev);
dev_err(imx412->dev, "failed to power-on the sensor\n");
ret = imx412_detect(imx412);
dev_err(imx412->dev, "failed to find sensor: %d\n", ret);
imx412->cur_mode = &supported_mode;
imx412->vblank = imx412->cur_mode->vblank;
ret = imx412_init_controls(imx412);
dev_err(imx412->dev, "failed to init controls: %d\n", ret);
imx412->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
imx412->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
v4l2_i2c_subdev_set_name(&imx412->sd, client, name, NULL);
imx412->pad.flags = MEDIA_PAD_FL_SOURCE;
ret = media_entity_pads_init(&imx412->sd.entity, 1, &imx412->pad);
dev_err(imx412->dev, "failed to init entity pads: %d\n", ret);
ret = v4l2_async_register_subdev_sensor(&imx412->sd);
dev_err(imx412->dev,
pm_runtime_set_active(imx412->dev);
pm_runtime_enable(imx412->dev);
pm_runtime_idle(imx412->dev);
media_entity_cleanup(&imx412->sd.entity);
v4l2_ctrl_handler_free(imx412->sd.ctrl_handler);
imx412_power_off(imx412->dev);
mutex_destroy(&imx412->mutex);
struct imx412 *imx412 = to_imx412(sd);
mutex_destroy(&imx412->mutex);
static inline struct imx412 *to_imx412(struct v4l2_subdev *subdev)
return container_of(subdev, struct imx412, sd);
static int imx412_read_reg(struct imx412 *imx412, u16 reg, u32 len, u32 *val)
struct i2c_client *client = v4l2_get_subdevdata(&imx412->sd);
static int imx412_write_reg(struct imx412 *imx412, u16 reg, u32 len, u32 val)
struct i2c_client *client = v4l2_get_subdevdata(&imx412->sd);
static int imx412_write_regs(struct imx412 *imx412,
ret = imx412_write_reg(imx412, regs[i].address, 1, regs[i].val);
static int imx412_update_controls(struct imx412 *imx412,
ret = __v4l2_ctrl_s_ctrl(imx412->link_freq_ctrl, mode->link_freq_idx);
ret = __v4l2_ctrl_s_ctrl(imx412->hblank_ctrl, mode->hblank);
return __v4l2_ctrl_modify_range(imx412->vblank_ctrl, mode->vblank_min,
static int imx412_update_exp_gain(struct imx412 *imx412, u32 exposure, u32 gain)
lpfr = imx412->vblank + imx412->cur_mode->height;
dev_dbg(imx412->dev, "Set exp %u, analog gain %u, lpfr %u\n",
ret = imx412_write_reg(imx412, IMX412_REG_HOLD, 1, 1);
ret = imx412_write_reg(imx412, IMX412_REG_LPFR, 2, lpfr);
ret = imx412_write_reg(imx412, IMX412_REG_EXPOSURE_CIT, 2, exposure);
ret = imx412_write_reg(imx412, IMX412_REG_AGAIN, 2, gain);
imx412_write_reg(imx412, IMX412_REG_HOLD, 1, 0);
struct imx412 *imx412 =
container_of(ctrl->handler, struct imx412, ctrl_handler);
imx412->vblank = imx412->vblank_ctrl->val;
dev_dbg(imx412->dev, "Received vblank %u, new lpfr %u\n",
imx412->vblank,
imx412->vblank + imx412->cur_mode->height);
ret = __v4l2_ctrl_modify_range(imx412->exp_ctrl,
imx412->vblank +
imx412->cur_mode->height -
if (!pm_runtime_get_if_in_use(imx412->dev))
analog_gain = imx412->again_ctrl->val;
dev_dbg(imx412->dev, "Received exp %u, analog gain %u\n",
ret = imx412_update_exp_gain(imx412, exposure, analog_gain);
pm_runtime_put(imx412->dev);
dev_err(imx412->dev, "Invalid control %d\n", ctrl->id);
static void imx412_fill_pad_format(struct imx412 *imx412,
struct imx412 *imx412 = to_imx412(sd);
mutex_lock(&imx412->mutex);
imx412_fill_pad_format(imx412, imx412->cur_mode, fmt);
mutex_unlock(&imx412->mutex);
struct imx412 *imx412 = to_imx412(sd);
mutex_lock(&imx412->mutex);
imx412_fill_pad_format(imx412, mode, fmt);
ret = imx412_update_controls(imx412, mode);
imx412->cur_mode = mode;
mutex_unlock(&imx412->mutex);
struct imx412 *imx412 = to_imx412(sd);
imx412_fill_pad_format(imx412, &supported_mode, &fmt);
static int imx412_start_streaming(struct imx412 *imx412)
reg_list = &imx412->cur_mode->reg_list;
ret = imx412_write_regs(imx412, reg_list->regs,
dev_err(imx412->dev, "fail to write initial registers\n");
ret = __v4l2_ctrl_handler_setup(imx412->sd.ctrl_handler);
dev_err(imx412->dev, "fail to setup handler\n");
ret = imx412_write_reg(imx412, IMX412_REG_MODE_SELECT,
dev_err(imx412->dev, "fail to start streaming\n");
static int imx412_stop_streaming(struct imx412 *imx412)
return imx412_write_reg(imx412, IMX412_REG_MODE_SELECT,
struct imx412 *imx412 = to_imx412(sd);
mutex_lock(&imx412->mutex);
ret = pm_runtime_resume_and_get(imx412->dev);
ret = imx412_start_streaming(imx412);
imx412_stop_streaming(imx412);
pm_runtime_put(imx412->dev);
mutex_unlock(&imx412->mutex);
pm_runtime_put(imx412->dev);
mutex_unlock(&imx412->mutex);
static int imx412_detect(struct imx412 *imx412)
ret = imx412_read_reg(imx412, IMX412_REG_ID, 2, &val);
dev_err(imx412->dev, "chip id mismatch: %x!=%x\n",
static int imx412_parse_hw_config(struct imx412 *imx412)
struct fwnode_handle *fwnode = dev_fwnode(imx412->dev);
imx412->reset_gpio = devm_gpiod_get_optional(imx412->dev, "reset",
if (IS_ERR(imx412->reset_gpio)) {
dev_err(imx412->dev, "failed to get reset gpio %pe\n",
imx412->reset_gpio);
return PTR_ERR(imx412->reset_gpio);
imx412->inclk = devm_v4l2_sensor_clk_get(imx412->dev, NULL);
if (IS_ERR(imx412->inclk))
return dev_err_probe(imx412->dev, PTR_ERR(imx412->inclk),
rate = clk_get_rate(imx412->inclk);
dev_err(imx412->dev, "inclk frequency mismatch\n");
imx412->supplies[i].supply = imx412_supply_names[i];
ret = devm_regulator_bulk_get(imx412->dev,
imx412->supplies);
dev_err(imx412->dev,
dev_err(imx412->dev, "no link frequencies defined\n");