int fimc_isp_subdev_create(struct fimc_isp *isp) { const struct v4l2_ctrl_ops *ops = &fimc_isp_ctrl_ops; struct v4l2_ctrl_handler *handler = &isp->ctrls.handler; struct v4l2_subdev *sd = &isp->subdev; struct fimc_isp_ctrls *ctrls = &isp->ctrls; int ret; mutex_init(&isp->subdev_lock); v4l2_subdev_init(sd, &fimc_is_subdev_ops); sd->owner = THIS_MODULE; sd->grp_id = GRP_ID_FIMC_IS; sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; snprintf(sd->name, sizeof(sd->name), "FIMC-IS-ISP"); isp->subdev_pads[FIMC_ISP_SD_PAD_SINK].flags = MEDIA_PAD_FL_SINK; isp->subdev_pads[FIMC_ISP_SD_PAD_SRC_FIFO].flags = MEDIA_PAD_FL_SOURCE; isp->subdev_pads[FIMC_ISP_SD_PAD_SRC_DMA].flags = MEDIA_PAD_FL_SOURCE; ret = media_entity_init(&sd->entity, FIMC_ISP_SD_PADS_NUM, isp->subdev_pads, 0); if (ret) return ret; v4l2_ctrl_handler_init(handler, 20); ctrls->saturation = v4l2_ctrl_new_std(handler, ops, V4L2_CID_SATURATION, -2, 2, 1, 0); ctrls->brightness = v4l2_ctrl_new_std(handler, ops, V4L2_CID_BRIGHTNESS, -4, 4, 1, 0); ctrls->contrast = v4l2_ctrl_new_std(handler, ops, V4L2_CID_CONTRAST, -2, 2, 1, 0); ctrls->sharpness = v4l2_ctrl_new_std(handler, ops, V4L2_CID_SHARPNESS, -2, 2, 1, 0); ctrls->hue = v4l2_ctrl_new_std(handler, ops, V4L2_CID_HUE, -2, 2, 1, 0); ctrls->auto_wb = v4l2_ctrl_new_std_menu(handler, ops, V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE, 8, ~0x14e, V4L2_WHITE_BALANCE_AUTO); ctrls->exposure = v4l2_ctrl_new_std(handler, ops, V4L2_CID_EXPOSURE_ABSOLUTE, -4, 4, 1, 0); ctrls->exp_metering = v4l2_ctrl_new_std_menu(handler, ops, V4L2_CID_EXPOSURE_METERING, 3, ~0xf, V4L2_EXPOSURE_METERING_AVERAGE); v4l2_ctrl_new_std_menu(handler, ops, V4L2_CID_POWER_LINE_FREQUENCY, V4L2_CID_POWER_LINE_FREQUENCY_AUTO, 0, V4L2_CID_POWER_LINE_FREQUENCY_AUTO); /* ISO sensitivity */ ctrls->auto_iso = v4l2_ctrl_new_std_menu(handler, ops, V4L2_CID_ISO_SENSITIVITY_AUTO, 1, 0, V4L2_ISO_SENSITIVITY_AUTO); ctrls->iso = v4l2_ctrl_new_int_menu(handler, ops, V4L2_CID_ISO_SENSITIVITY, ARRAY_SIZE(iso_qmenu) - 1, ARRAY_SIZE(iso_qmenu)/2 - 1, iso_qmenu); ctrls->aewb_lock = v4l2_ctrl_new_std(handler, ops, V4L2_CID_3A_LOCK, 0, 0x3, 0, 0); /* TODO: Add support for NEGATIVE_COLOR option */ ctrls->colorfx = v4l2_ctrl_new_std_menu(handler, ops, V4L2_CID_COLORFX, V4L2_COLORFX_SET_CBCR + 1, ~0x1000f, V4L2_COLORFX_NONE); if (handler->error) { media_entity_cleanup(&sd->entity); return handler->error; } v4l2_ctrl_auto_cluster(2, &ctrls->auto_iso, V4L2_ISO_SENSITIVITY_MANUAL, false); sd->ctrl_handler = handler; sd->internal_ops = &fimc_is_subdev_internal_ops; sd->entity.ops = &fimc_is_subdev_media_ops; v4l2_set_subdevdata(sd, isp); __isp_subdev_set_default_format(isp); return 0; }
/* Initialize control handlers */ static int ov13858_init_controls(struct ov13858 *ov13858) { struct i2c_client *client = v4l2_get_subdevdata(&ov13858->sd); struct v4l2_ctrl_handler *ctrl_hdlr; s64 exposure_max; s64 vblank_def; s64 vblank_min; s64 hblank; s64 pixel_rate_min; s64 pixel_rate_max; const struct ov13858_mode *mode; int ret; ctrl_hdlr = &ov13858->ctrl_handler; ret = v4l2_ctrl_handler_init(ctrl_hdlr, 8); if (ret) return ret; mutex_init(&ov13858->mutex); ctrl_hdlr->lock = &ov13858->mutex; ov13858->link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr, &ov13858_ctrl_ops, V4L2_CID_LINK_FREQ, OV13858_NUM_OF_LINK_FREQS - 1, 0, link_freq_menu_items); ov13858->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; pixel_rate_max = link_freq_to_pixel_rate(link_freq_menu_items[0]); pixel_rate_min = link_freq_to_pixel_rate(link_freq_menu_items[1]); /* By default, PIXEL_RATE is read only */ ov13858->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &ov13858_ctrl_ops, V4L2_CID_PIXEL_RATE, pixel_rate_min, pixel_rate_max, 1, pixel_rate_max); mode = ov13858->cur_mode; vblank_def = mode->vts_def - mode->height; vblank_min = mode->vts_min - mode->height; ov13858->vblank = v4l2_ctrl_new_std( ctrl_hdlr, &ov13858_ctrl_ops, V4L2_CID_VBLANK, vblank_min, OV13858_VTS_MAX - mode->height, 1, vblank_def); hblank = link_freq_configs[mode->link_freq_index].pixels_per_line - mode->width; ov13858->hblank = v4l2_ctrl_new_std( ctrl_hdlr, &ov13858_ctrl_ops, V4L2_CID_HBLANK, hblank, hblank, 1, hblank); ov13858->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; exposure_max = mode->vts_def - 8; ov13858->exposure = v4l2_ctrl_new_std( ctrl_hdlr, &ov13858_ctrl_ops, V4L2_CID_EXPOSURE, OV13858_EXPOSURE_MIN, exposure_max, OV13858_EXPOSURE_STEP, OV13858_EXPOSURE_DEFAULT); v4l2_ctrl_new_std(ctrl_hdlr, &ov13858_ctrl_ops, V4L2_CID_ANALOGUE_GAIN, OV13858_ANA_GAIN_MIN, OV13858_ANA_GAIN_MAX, OV13858_ANA_GAIN_STEP, OV13858_ANA_GAIN_DEFAULT); /* Digital gain */ v4l2_ctrl_new_std(ctrl_hdlr, &ov13858_ctrl_ops, V4L2_CID_DIGITAL_GAIN, OV13858_DGTL_GAIN_MIN, OV13858_DGTL_GAIN_MAX, OV13858_DGTL_GAIN_STEP, OV13858_DGTL_GAIN_DEFAULT); v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &ov13858_ctrl_ops, V4L2_CID_TEST_PATTERN, ARRAY_SIZE(ov13858_test_pattern_menu) - 1, 0, 0, ov13858_test_pattern_menu); if (ctrl_hdlr->error) { ret = ctrl_hdlr->error; dev_err(&client->dev, "%s control init failed (%d)\n", __func__, ret); goto error; } ov13858->sd.ctrl_handler = ctrl_hdlr; return 0; error: v4l2_ctrl_handler_free(ctrl_hdlr); mutex_destroy(&ov13858->mutex); return ret; }