Lines Matching +full:capture +full:- +full:sd +full:- +full:lines
1 // SPDX-License-Identifier: GPL-2.0
26 #include <media/v4l2-cci.h>
27 #include <media/v4l2-ctrls.h>
28 #include <media/v4l2-device.h>
29 #include <media/v4l2-fwnode.h>
30 #include <media/v4l2-mediabus.h>
156 /* V-timing */
163 /* To Access Addresses 3000-5fff, send the following commands */
204 /* 2-Lane CSI Mode */
218 /* 4-Lane CSI Mode */
265 * - no flip
266 * - h flip
267 * - v flip
268 * - h&v flips
283 * Initialisation delay between XCLR low->high and the moment when the sensor
284 * can start capture (i.e. can leave software stanby) must be not less than:
296 * This start-up time can be optimized a bit more, if we start the writes
299 * ensure that capture is not started before (t4+t5).
303 * case of DT for regulator-fixed one should define the startup-delay-us
338 struct v4l2_subdev sd; member
364 return container_of(_sd, struct imx219, sd); in to_imx219()
379 i = (i & ~3) | (imx219->vflip->val ? 2 : 0) | in imx219_get_format_code()
380 (imx219->hflip->val ? 1 : 0); in imx219_get_format_code()
387 switch (format->code) { in imx219_get_format_bpp()
409 u32 hbin = crop->width / format->width; in imx219_get_binning()
410 u32 vbin = crop->height / format->height; in imx219_get_binning()
441 /* -----------------------------------------------------------------------------
448 container_of(ctrl->handler, struct imx219, ctrl_handler); in imx219_set_ctrl()
449 struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd); in imx219_set_ctrl()
455 state = v4l2_subdev_get_locked_active_state(&imx219->sd); in imx219_set_ctrl()
459 if (ctrl->id == V4L2_CID_VBLANK) { in imx219_set_ctrl()
463 exposure_max = format->height + ctrl->val - 4; in imx219_set_ctrl()
466 __v4l2_ctrl_modify_range(imx219->exposure, in imx219_set_ctrl()
467 imx219->exposure->minimum, in imx219_set_ctrl()
468 exposure_max, imx219->exposure->step, in imx219_set_ctrl()
476 if (pm_runtime_get_if_in_use(&client->dev) == 0) in imx219_set_ctrl()
479 switch (ctrl->id) { in imx219_set_ctrl()
481 cci_write(imx219->regmap, IMX219_REG_ANALOG_GAIN, in imx219_set_ctrl()
482 ctrl->val, &ret); in imx219_set_ctrl()
485 cci_write(imx219->regmap, IMX219_REG_EXPOSURE, in imx219_set_ctrl()
486 ctrl->val / rate_factor, &ret); in imx219_set_ctrl()
489 cci_write(imx219->regmap, IMX219_REG_DIGITAL_GAIN, in imx219_set_ctrl()
490 ctrl->val, &ret); in imx219_set_ctrl()
493 cci_write(imx219->regmap, IMX219_REG_TEST_PATTERN, in imx219_set_ctrl()
494 imx219_test_pattern_val[ctrl->val], &ret); in imx219_set_ctrl()
498 cci_write(imx219->regmap, IMX219_REG_ORIENTATION, in imx219_set_ctrl()
499 imx219->hflip->val | imx219->vflip->val << 1, &ret); in imx219_set_ctrl()
502 cci_write(imx219->regmap, IMX219_REG_FRM_LENGTH_A, in imx219_set_ctrl()
503 (format->height + ctrl->val) / rate_factor, &ret); in imx219_set_ctrl()
506 cci_write(imx219->regmap, IMX219_REG_LINE_LENGTH_A, in imx219_set_ctrl()
507 format->width + ctrl->val, &ret); in imx219_set_ctrl()
510 cci_write(imx219->regmap, IMX219_REG_TESTP_RED, in imx219_set_ctrl()
511 ctrl->val, &ret); in imx219_set_ctrl()
514 cci_write(imx219->regmap, IMX219_REG_TESTP_GREENR, in imx219_set_ctrl()
515 ctrl->val, &ret); in imx219_set_ctrl()
518 cci_write(imx219->regmap, IMX219_REG_TESTP_BLUE, in imx219_set_ctrl()
519 ctrl->val, &ret); in imx219_set_ctrl()
522 cci_write(imx219->regmap, IMX219_REG_TESTP_GREENB, in imx219_set_ctrl()
523 ctrl->val, &ret); in imx219_set_ctrl()
526 dev_info(&client->dev, in imx219_set_ctrl()
528 ctrl->id, ctrl->val); in imx219_set_ctrl()
529 ret = -EINVAL; in imx219_set_ctrl()
533 pm_runtime_put(&client->dev); in imx219_set_ctrl()
544 return (imx219->lanes == 2) ? IMX219_PIXEL_RATE : IMX219_PIXEL_RATE_4LANE; in imx219_get_pixel_rate()
550 struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd); in imx219_init_controls()
557 ctrl_hdlr = &imx219->ctrl_handler; in imx219_init_controls()
563 imx219->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, in imx219_init_controls()
569 imx219->link_freq = in imx219_init_controls()
572 ARRAY_SIZE(imx219_link_freq_menu) - 1, 0, in imx219_init_controls()
573 (imx219->lanes == 2) ? imx219_link_freq_menu : in imx219_init_controls()
575 if (imx219->link_freq) in imx219_init_controls()
576 imx219->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; in imx219_init_controls()
579 imx219->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, in imx219_init_controls()
581 IMX219_FLL_MAX - mode->height, 1, in imx219_init_controls()
582 mode->fll_def - mode->height); in imx219_init_controls()
583 imx219->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, in imx219_init_controls()
585 IMX219_LLP_MIN - mode->width, in imx219_init_controls()
586 IMX219_LLP_MAX - mode->width, 1, in imx219_init_controls()
587 IMX219_LLP_MIN - mode->width); in imx219_init_controls()
588 exposure_max = mode->fll_def - 4; in imx219_init_controls()
591 imx219->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, in imx219_init_controls()
605 imx219->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, in imx219_init_controls()
607 if (imx219->hflip) in imx219_init_controls()
608 imx219->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; in imx219_init_controls()
610 imx219->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, in imx219_init_controls()
612 if (imx219->vflip) in imx219_init_controls()
613 imx219->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; in imx219_init_controls()
617 ARRAY_SIZE(imx219_test_pattern_menu) - 1, in imx219_init_controls()
635 if (ctrl_hdlr->error) { in imx219_init_controls()
636 ret = ctrl_hdlr->error; in imx219_init_controls()
637 dev_err_probe(&client->dev, ret, "Control init failed\n"); in imx219_init_controls()
641 ret = v4l2_fwnode_device_parse(&client->dev, &props); in imx219_init_controls()
650 imx219->sd.ctrl_handler = ctrl_hdlr; in imx219_init_controls()
662 v4l2_ctrl_handler_free(imx219->sd.ctrl_handler); in imx219_free_controls()
665 /* -----------------------------------------------------------------------------
682 cci_write(imx219->regmap, IMX219_REG_X_ADD_STA_A, in imx219_set_framefmt()
683 crop->left - IMX219_PIXEL_ARRAY_LEFT, &ret); in imx219_set_framefmt()
684 cci_write(imx219->regmap, IMX219_REG_X_ADD_END_A, in imx219_set_framefmt()
685 crop->left - IMX219_PIXEL_ARRAY_LEFT + crop->width - 1, &ret); in imx219_set_framefmt()
686 cci_write(imx219->regmap, IMX219_REG_Y_ADD_STA_A, in imx219_set_framefmt()
687 crop->top - IMX219_PIXEL_ARRAY_TOP, &ret); in imx219_set_framefmt()
688 cci_write(imx219->regmap, IMX219_REG_Y_ADD_END_A, in imx219_set_framefmt()
689 crop->top - IMX219_PIXEL_ARRAY_TOP + crop->height - 1, &ret); in imx219_set_framefmt()
692 cci_write(imx219->regmap, IMX219_REG_BINNING_MODE_H, bin_h, &ret); in imx219_set_framefmt()
693 cci_write(imx219->regmap, IMX219_REG_BINNING_MODE_V, bin_v, &ret); in imx219_set_framefmt()
695 cci_write(imx219->regmap, IMX219_REG_X_OUTPUT_SIZE, in imx219_set_framefmt()
696 format->width, &ret); in imx219_set_framefmt()
697 cci_write(imx219->regmap, IMX219_REG_Y_OUTPUT_SIZE, in imx219_set_framefmt()
698 format->height, &ret); in imx219_set_framefmt()
700 cci_write(imx219->regmap, IMX219_REG_TP_WINDOW_WIDTH, in imx219_set_framefmt()
701 format->width, &ret); in imx219_set_framefmt()
702 cci_write(imx219->regmap, IMX219_REG_TP_WINDOW_HEIGHT, in imx219_set_framefmt()
703 format->height, &ret); in imx219_set_framefmt()
705 cci_write(imx219->regmap, IMX219_REG_CSI_DATA_FORMAT_A, in imx219_set_framefmt()
707 cci_write(imx219->regmap, IMX219_REG_OPPXCK_DIV, bpp, &ret); in imx219_set_framefmt()
715 return cci_multi_reg_write(imx219->regmap, in imx219_configure_lanes()
716 imx219->lanes == 2 ? imx219_2lane_regs : imx219_4lane_regs, in imx219_configure_lanes()
717 imx219->lanes == 2 ? ARRAY_SIZE(imx219_2lane_regs) : in imx219_configure_lanes()
724 struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd); in imx219_start_streaming()
727 ret = pm_runtime_resume_and_get(&client->dev); in imx219_start_streaming()
732 ret = cci_multi_reg_write(imx219->regmap, imx219_common_regs, in imx219_start_streaming()
735 dev_err(&client->dev, "%s failed to send mfg header\n", __func__); in imx219_start_streaming()
742 dev_err(&client->dev, "%s failed to configure lanes\n", __func__); in imx219_start_streaming()
749 dev_err(&client->dev, "%s failed to set frame format: %d\n", in imx219_start_streaming()
755 ret = __v4l2_ctrl_handler_setup(imx219->sd.ctrl_handler); in imx219_start_streaming()
760 ret = cci_write(imx219->regmap, IMX219_REG_MODE_SELECT, in imx219_start_streaming()
766 __v4l2_ctrl_grab(imx219->vflip, true); in imx219_start_streaming()
767 __v4l2_ctrl_grab(imx219->hflip, true); in imx219_start_streaming()
772 pm_runtime_put(&client->dev); in imx219_start_streaming()
778 struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd); in imx219_stop_streaming()
782 ret = cci_write(imx219->regmap, IMX219_REG_MODE_SELECT, in imx219_stop_streaming()
785 dev_err(&client->dev, "%s failed to set stream\n", __func__); in imx219_stop_streaming()
787 __v4l2_ctrl_grab(imx219->vflip, false); in imx219_stop_streaming()
788 __v4l2_ctrl_grab(imx219->hflip, false); in imx219_stop_streaming()
790 pm_runtime_put(&client->dev); in imx219_stop_streaming()
793 static int imx219_set_stream(struct v4l2_subdev *sd, int enable) in imx219_set_stream() argument
795 struct imx219 *imx219 = to_imx219(sd); in imx219_set_stream()
799 state = v4l2_subdev_lock_and_get_active_state(sd); in imx219_set_stream()
815 fmt->code = imx219_get_format_code(imx219, code); in imx219_update_pad_format()
816 fmt->width = mode->width; in imx219_update_pad_format()
817 fmt->height = mode->height; in imx219_update_pad_format()
818 fmt->field = V4L2_FIELD_NONE; in imx219_update_pad_format()
819 fmt->colorspace = V4L2_COLORSPACE_RAW; in imx219_update_pad_format()
820 fmt->ycbcr_enc = V4L2_YCBCR_ENC_601; in imx219_update_pad_format()
821 fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE; in imx219_update_pad_format()
822 fmt->xfer_func = V4L2_XFER_FUNC_NONE; in imx219_update_pad_format()
825 static int imx219_enum_mbus_code(struct v4l2_subdev *sd, in imx219_enum_mbus_code() argument
829 struct imx219 *imx219 = to_imx219(sd); in imx219_enum_mbus_code()
831 if (code->index >= (ARRAY_SIZE(imx219_mbus_formats) / 4)) in imx219_enum_mbus_code()
832 return -EINVAL; in imx219_enum_mbus_code()
834 code->code = imx219_get_format_code(imx219, imx219_mbus_formats[code->index * 4]); in imx219_enum_mbus_code()
839 static int imx219_enum_frame_size(struct v4l2_subdev *sd, in imx219_enum_frame_size() argument
843 struct imx219 *imx219 = to_imx219(sd); in imx219_enum_frame_size()
846 if (fse->index >= ARRAY_SIZE(supported_modes)) in imx219_enum_frame_size()
847 return -EINVAL; in imx219_enum_frame_size()
849 code = imx219_get_format_code(imx219, fse->code); in imx219_enum_frame_size()
850 if (fse->code != code) in imx219_enum_frame_size()
851 return -EINVAL; in imx219_enum_frame_size()
853 fse->min_width = supported_modes[fse->index].width; in imx219_enum_frame_size()
854 fse->max_width = fse->min_width; in imx219_enum_frame_size()
855 fse->min_height = supported_modes[fse->index].height; in imx219_enum_frame_size()
856 fse->max_height = fse->min_height; in imx219_enum_frame_size()
861 static int imx219_set_pad_format(struct v4l2_subdev *sd, in imx219_set_pad_format() argument
865 struct imx219 *imx219 = to_imx219(sd); in imx219_set_pad_format()
873 prev_line_len = format->width + imx219->hblank->val; in imx219_set_pad_format()
878 fmt->format.width, fmt->format.height); in imx219_set_pad_format()
880 imx219_update_pad_format(imx219, mode, &fmt->format, fmt->format.code); in imx219_set_pad_format()
881 *format = fmt->format; in imx219_set_pad_format()
887 bin_h = min(IMX219_PIXEL_ARRAY_WIDTH / format->width, 2U); in imx219_set_pad_format()
888 bin_v = min(IMX219_PIXEL_ARRAY_HEIGHT / format->height, 2U); in imx219_set_pad_format()
891 crop->width = format->width * bin_h; in imx219_set_pad_format()
892 crop->height = format->height * bin_v; in imx219_set_pad_format()
893 crop->left = (IMX219_NATIVE_WIDTH - crop->width) / 2; in imx219_set_pad_format()
894 crop->top = (IMX219_NATIVE_HEIGHT - crop->height) / 2; in imx219_set_pad_format()
896 if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { in imx219_set_pad_format()
903 __v4l2_ctrl_modify_range(imx219->vblank, IMX219_VBLANK_MIN, in imx219_set_pad_format()
904 IMX219_FLL_MAX - mode->height, 1, in imx219_set_pad_format()
905 mode->fll_def - mode->height); in imx219_set_pad_format()
906 __v4l2_ctrl_s_ctrl(imx219->vblank, in imx219_set_pad_format()
907 mode->fll_def - mode->height); in imx219_set_pad_format()
909 exposure_max = mode->fll_def - 4; in imx219_set_pad_format()
912 __v4l2_ctrl_modify_range(imx219->exposure, in imx219_set_pad_format()
913 imx219->exposure->minimum, in imx219_set_pad_format()
914 exposure_max, imx219->exposure->step, in imx219_set_pad_format()
920 * operates on two lines together. So we switch to a higher in imx219_set_pad_format()
926 __v4l2_ctrl_modify_range(imx219->hblank, llp_min - mode->width, in imx219_set_pad_format()
927 IMX219_LLP_MAX - mode->width, 1, in imx219_set_pad_format()
928 llp_min - mode->width); in imx219_set_pad_format()
936 hblank = prev_line_len - mode->width; in imx219_set_pad_format()
937 __v4l2_ctrl_s_ctrl(imx219->hblank, hblank); in imx219_set_pad_format()
942 __v4l2_ctrl_modify_range(imx219->pixel_rate, pixel_rate, in imx219_set_pad_format()
949 static int imx219_get_selection(struct v4l2_subdev *sd, in imx219_get_selection() argument
953 switch (sel->target) { in imx219_get_selection()
955 sel->r = *v4l2_subdev_state_get_crop(state, 0); in imx219_get_selection()
959 sel->r.top = 0; in imx219_get_selection()
960 sel->r.left = 0; in imx219_get_selection()
961 sel->r.width = IMX219_NATIVE_WIDTH; in imx219_get_selection()
962 sel->r.height = IMX219_NATIVE_HEIGHT; in imx219_get_selection()
968 sel->r.top = IMX219_PIXEL_ARRAY_TOP; in imx219_get_selection()
969 sel->r.left = IMX219_PIXEL_ARRAY_LEFT; in imx219_get_selection()
970 sel->r.width = IMX219_PIXEL_ARRAY_WIDTH; in imx219_get_selection()
971 sel->r.height = IMX219_PIXEL_ARRAY_HEIGHT; in imx219_get_selection()
976 return -EINVAL; in imx219_get_selection()
979 static int imx219_init_state(struct v4l2_subdev *sd, in imx219_init_state() argument
992 imx219_set_pad_format(sd, state, &fmt); in imx219_init_state()
1018 /* -----------------------------------------------------------------------------
1024 struct v4l2_subdev *sd = dev_get_drvdata(dev); in imx219_power_on() local
1025 struct imx219 *imx219 = to_imx219(sd); in imx219_power_on()
1029 imx219->supplies); in imx219_power_on()
1036 ret = clk_prepare_enable(imx219->xclk); in imx219_power_on()
1043 gpiod_set_value_cansleep(imx219->reset_gpio, 1); in imx219_power_on()
1050 regulator_bulk_disable(IMX219_NUM_SUPPLIES, imx219->supplies); in imx219_power_on()
1057 struct v4l2_subdev *sd = dev_get_drvdata(dev); in imx219_power_off() local
1058 struct imx219 *imx219 = to_imx219(sd); in imx219_power_off()
1060 gpiod_set_value_cansleep(imx219->reset_gpio, 0); in imx219_power_off()
1061 regulator_bulk_disable(IMX219_NUM_SUPPLIES, imx219->supplies); in imx219_power_off()
1062 clk_disable_unprepare(imx219->xclk); in imx219_power_off()
1067 /* -----------------------------------------------------------------------------
1073 struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd); in imx219_get_regulators()
1077 imx219->supplies[i].supply = imx219_supply_name[i]; in imx219_get_regulators()
1079 return devm_regulator_bulk_get(&client->dev, in imx219_get_regulators()
1081 imx219->supplies); in imx219_get_regulators()
1087 struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd); in imx219_identify_module()
1091 ret = cci_read(imx219->regmap, IMX219_REG_CHIP_ID, &val, NULL); in imx219_identify_module()
1093 return dev_err_probe(&client->dev, ret, in imx219_identify_module()
1098 return dev_err_probe(&client->dev, -EIO, in imx219_identify_module()
1112 int ret = -EINVAL; in imx219_check_hwcfg()
1116 return dev_err_probe(dev, -EINVAL, "endpoint node not found\n"); in imx219_check_hwcfg()
1119 dev_err_probe(dev, -EINVAL, "could not parse endpoint\n"); in imx219_check_hwcfg()
1126 dev_err_probe(dev, -EINVAL, in imx219_check_hwcfg()
1130 imx219->lanes = ep_cfg.bus.mipi_csi2.num_data_lanes; in imx219_check_hwcfg()
1133 switch (imx219->lanes) { in imx219_check_hwcfg()
1161 ret = -EINVAL; in imx219_check_hwcfg()
1162 dev_err_probe(dev, -EINVAL, in imx219_check_hwcfg()
1176 struct device *dev = &client->dev; in imx219_probe()
1180 imx219 = devm_kzalloc(&client->dev, sizeof(*imx219), GFP_KERNEL); in imx219_probe()
1182 return -ENOMEM; in imx219_probe()
1184 v4l2_i2c_subdev_init(&imx219->sd, client, &imx219_subdev_ops); in imx219_probe()
1185 imx219->sd.internal_ops = &imx219_internal_ops; in imx219_probe()
1189 return -EINVAL; in imx219_probe()
1191 imx219->regmap = devm_cci_regmap_init_i2c(client, 16); in imx219_probe()
1192 if (IS_ERR(imx219->regmap)) in imx219_probe()
1193 return dev_err_probe(dev, PTR_ERR(imx219->regmap), in imx219_probe()
1197 imx219->xclk = devm_clk_get(dev, NULL); in imx219_probe()
1198 if (IS_ERR(imx219->xclk)) in imx219_probe()
1199 return dev_err_probe(dev, PTR_ERR(imx219->xclk), in imx219_probe()
1202 imx219->xclk_freq = clk_get_rate(imx219->xclk); in imx219_probe()
1203 if (imx219->xclk_freq != IMX219_XCLK_FREQ) in imx219_probe()
1204 return dev_err_probe(dev, -EINVAL, in imx219_probe()
1206 imx219->xclk_freq); in imx219_probe()
1213 imx219->reset_gpio = devm_gpiod_get_optional(dev, "reset", in imx219_probe()
1229 * Sensor doesn't enter LP-11 state upon power up until and unless in imx219_probe()
1231 * streaming -> standby in imx219_probe()
1233 ret = cci_write(imx219->regmap, IMX219_REG_MODE_SELECT, in imx219_probe()
1241 ret = cci_write(imx219->regmap, IMX219_REG_MODE_SELECT, in imx219_probe()
1253 imx219->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; in imx219_probe()
1254 imx219->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; in imx219_probe()
1257 imx219->pad.flags = MEDIA_PAD_FL_SOURCE; in imx219_probe()
1259 ret = media_entity_pads_init(&imx219->sd.entity, 1, &imx219->pad); in imx219_probe()
1265 imx219->sd.state_lock = imx219->ctrl_handler.lock; in imx219_probe()
1266 ret = v4l2_subdev_init_finalize(&imx219->sd); in imx219_probe()
1275 ret = v4l2_async_register_subdev_sensor(&imx219->sd); in imx219_probe()
1278 "failed to register sensor sub-device\n"); in imx219_probe()
1287 v4l2_subdev_cleanup(&imx219->sd); in imx219_probe()
1292 media_entity_cleanup(&imx219->sd.entity); in imx219_probe()
1305 struct v4l2_subdev *sd = i2c_get_clientdata(client); in imx219_remove() local
1306 struct imx219 *imx219 = to_imx219(sd); in imx219_remove()
1308 v4l2_async_unregister_subdev(sd); in imx219_remove()
1309 v4l2_subdev_cleanup(sd); in imx219_remove()
1310 media_entity_cleanup(&sd->entity); in imx219_remove()
1313 pm_runtime_disable(&client->dev); in imx219_remove()
1314 if (!pm_runtime_status_suspended(&client->dev)) { in imx219_remove()
1315 imx219_power_off(&client->dev); in imx219_remove()
1316 pm_runtime_set_suspended(&client->dev); in imx219_remove()