/* ************************************************************************* * Rockchip driver for CIF ISP 1.0 * (Based on Intel driver for sofiaxxx) * * Copyright (C) 2015 Intel Mobile Communications GmbH * Copyright (C) 2016 Fuzhou Rockchip Electronics Co., Ltd. * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. ************************************************************************* */ #include #include #include #include #include #include "cif_isp10.h" #include #include #include /* ===================== */ /* Image Source */ /* ===================== */ void *cif_isp10_img_src_v4l2_i2c_subdev_to_img_src( struct device *dev, struct pltfrm_soc_cfg *soc_cfg) { int ret = 0; struct i2c_client *client; struct v4l2_subdev *subdev; client = i2c_verify_client(dev); if (IS_ERR_OR_NULL(client)) { cif_isp10_pltfrm_pr_err(dev, "not an I2C device\n"); ret = -EINVAL; goto err; } subdev = i2c_get_clientdata(client); if (IS_ERR_OR_NULL(subdev)) return subdev; ret = v4l2_subdev_call(subdev, core, ioctl, PLTFRM_CIFCAM_ATTACH, (void *)soc_cfg); if (ret != 0) goto err; return (void *)subdev; err: cif_isp10_pltfrm_pr_err(NULL, "failed with error %d\n", ret); return ERR_PTR(ret); } static enum cif_isp10_pix_fmt img_src_v4l2_subdev_pix_fmt2cif_isp10_pix_fmt( int img_src_pix_fmt) { switch (img_src_pix_fmt) { case MEDIA_BUS_FMT_Y8_1X8: return CIF_YUV400; case MEDIA_BUS_FMT_Y10_1X10: return CIF_Y10; case MEDIA_BUS_FMT_Y12_1X12: return CIF_Y12; case MEDIA_BUS_FMT_YUYV8_1_5X8: case MEDIA_BUS_FMT_YUYV8_2X8: case MEDIA_BUS_FMT_YUYV10_2X10: case MEDIA_BUS_FMT_YUYV8_1X16: case MEDIA_BUS_FMT_YUYV10_1X20: return CIF_YUV422I; case MEDIA_BUS_FMT_YVYU8_1_5X8: case MEDIA_BUS_FMT_YVYU8_2X8: case MEDIA_BUS_FMT_YVYU10_2X10: case MEDIA_BUS_FMT_YVYU8_1X16: case MEDIA_BUS_FMT_YVYU10_1X20: return CIF_YVU422I; case MEDIA_BUS_FMT_UYVY8_1_5X8: case MEDIA_BUS_FMT_UYVY8_2X8: case MEDIA_BUS_FMT_UYVY8_1X16: return CIF_UYV422I; case MEDIA_BUS_FMT_RGB565_2X8_BE: case MEDIA_BUS_FMT_RGB565_2X8_LE: return CIF_RGB565; case MEDIA_BUS_FMT_RGB666_1X18: return CIF_RGB666; case MEDIA_BUS_FMT_RGB888_1X24: case MEDIA_BUS_FMT_RGB888_2X12_BE: case MEDIA_BUS_FMT_RGB888_2X12_LE: return CIF_RGB888; case MEDIA_BUS_FMT_SBGGR8_1X8: return CIF_BAYER_SBGGR8; case MEDIA_BUS_FMT_SGBRG8_1X8: return CIF_BAYER_SGBRG8; case MEDIA_BUS_FMT_SGRBG8_1X8: return CIF_BAYER_SGRBG8; case MEDIA_BUS_FMT_SRGGB8_1X8: return CIF_BAYER_SRGGB8; case MEDIA_BUS_FMT_SBGGR10_ALAW8_1X8: case MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8: case MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_BE: case MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE: case MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_BE: case MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_LE: case MEDIA_BUS_FMT_SBGGR10_1X10: return CIF_BAYER_SBGGR10; case MEDIA_BUS_FMT_SGBRG10_ALAW8_1X8: case MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8: case MEDIA_BUS_FMT_SGBRG10_1X10: return CIF_BAYER_SGBRG10; case MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8: case MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8: case MEDIA_BUS_FMT_SGRBG10_1X10: return CIF_BAYER_SGRBG10; case MEDIA_BUS_FMT_SRGGB10_ALAW8_1X8: case MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8: case MEDIA_BUS_FMT_SRGGB10_1X10: return CIF_BAYER_SRGGB10; case MEDIA_BUS_FMT_SBGGR12_1X12: return CIF_BAYER_SBGGR12; case MEDIA_BUS_FMT_SGBRG12_1X12: return CIF_BAYER_SGBRG12; case MEDIA_BUS_FMT_SGRBG12_1X12: return CIF_BAYER_SGRBG12; case MEDIA_BUS_FMT_SRGGB12_1X12: return CIF_BAYER_SRGGB12; case MEDIA_BUS_FMT_JPEG_1X8: return CIF_JPEG; default: return CIF_UNKNOWN_FORMAT; } } static int cif_isp10_pix_fmt2img_src_v4l2_subdev_pix_fmt( enum cif_isp10_pix_fmt cif_isp10_pix_fmt) { switch (cif_isp10_pix_fmt) { case CIF_Y10: return MEDIA_BUS_FMT_Y10_1X10; case CIF_Y12: return MEDIA_BUS_FMT_Y12_1X12; case CIF_YUV400: return MEDIA_BUS_FMT_Y8_1X8; case CIF_YUV422I: return MEDIA_BUS_FMT_YUYV8_2X8; case CIF_YVU422I: return MEDIA_BUS_FMT_YVYU8_2X8; case CIF_UYV422I: return MEDIA_BUS_FMT_UYVY8_2X8; case CIF_RGB565: return MEDIA_BUS_FMT_RGB565_2X8_LE; case CIF_RGB666: return MEDIA_BUS_FMT_RGB666_1X18; case CIF_RGB888: return MEDIA_BUS_FMT_RGB888_1X24; case CIF_BAYER_SBGGR8: return MEDIA_BUS_FMT_SBGGR8_1X8; case CIF_BAYER_SGBRG8: return MEDIA_BUS_FMT_SGBRG8_1X8; case CIF_BAYER_SGRBG8: return MEDIA_BUS_FMT_SGRBG8_1X8; case CIF_BAYER_SRGGB8: return MEDIA_BUS_FMT_SRGGB8_1X8; case CIF_BAYER_SBGGR10: return MEDIA_BUS_FMT_SBGGR10_1X10; case CIF_BAYER_SGBRG10: return MEDIA_BUS_FMT_SGBRG10_1X10; case CIF_BAYER_SGRBG10: return MEDIA_BUS_FMT_SGRBG10_1X10; case CIF_BAYER_SRGGB10: return MEDIA_BUS_FMT_SRGGB10_1X10; case CIF_BAYER_SBGGR12: return MEDIA_BUS_FMT_SBGGR12_1X12; case CIF_BAYER_SGBRG12: return MEDIA_BUS_FMT_SGBRG12_1X12; case CIF_BAYER_SGRBG12: return MEDIA_BUS_FMT_SGRBG12_1X12; case CIF_BAYER_SRGGB12: return MEDIA_BUS_FMT_SRGGB12_1X12; case CIF_JPEG: return MEDIA_BUS_FMT_JPEG_1X8; default: return -EINVAL; } } static int cif_isp10_v4l2_cid2v4l2_cid(u32 cif_isp10_cid) { switch (cif_isp10_cid) { case CIF_ISP10_CID_FLASH_MODE: return V4L2_CID_FLASH_LED_MODE; case CIF_ISP10_CID_AUTO_GAIN: return V4L2_CID_AUTOGAIN; case CIF_ISP10_CID_AUTO_EXPOSURE: return V4L2_EXPOSURE_AUTO; case CIF_ISP10_CID_AUTO_WHITE_BALANCE: return V4L2_CID_AUTO_WHITE_BALANCE; case CIF_ISP10_CID_BLACK_LEVEL: return V4L2_CID_BLACK_LEVEL; case CIF_ISP10_CID_WB_TEMPERATURE: return V4L2_CID_WHITE_BALANCE_TEMPERATURE; case CIF_ISP10_CID_EXPOSURE_TIME: return V4L2_CID_EXPOSURE; case CIF_ISP10_CID_ANALOG_GAIN: return V4L2_CID_GAIN; case CIF_ISP10_CID_FOCUS_ABSOLUTE: return V4L2_CID_FOCUS_ABSOLUTE; case CIF_ISP10_CID_AUTO_N_PRESET_WHITE_BALANCE: return V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE; case CIF_ISP10_CID_SCENE_MODE: return V4L2_CID_SCENE_MODE; case CIF_ISP10_CID_ISO_SENSITIVITY: return V4L2_CID_ISO_SENSITIVITY; case CIF_ISP10_CID_AUTO_FPS: return RK_V4L2_CID_AUTO_FPS; case CIF_ISP10_CID_VBLANKING: return RK_V4L2_CID_VBLANKING; case CIF_ISP10_CID_HFLIP: return V4L2_CID_HFLIP; case CIF_ISP10_CID_VFLIP: return V4L2_CID_VFLIP; case CIF_ISP10_CID_MIN_BUFFER_FOR_CAPTURE: return V4L2_CID_MIN_BUFFERS_FOR_CAPTURE; case CIF_ISP10_CID_TEST_PATTERN: return V4L2_CID_TEST_PATTERN; default: cif_isp10_pltfrm_pr_err(NULL, "unknown/unsupported CIF ISP20 ID %d\n", cif_isp10_cid); break; } return -EINVAL; } int cif_isp10_img_src_v4l2_subdev_s_streaming( void *img_src, bool enable) { struct v4l2_subdev *subdev = img_src; if (enable) return v4l2_subdev_call(subdev, video, s_stream, 1); else return v4l2_subdev_call(subdev, video, s_stream, 0); } int cif_isp10_img_src_v4l2_subdev_s_power( void *img_src, bool on) { struct v4l2_subdev *subdev = img_src; if (on) return v4l2_subdev_call(subdev, core, s_power, 1); else return v4l2_subdev_call(subdev, core, s_power, 0); } int cif_isp10_img_src_v4l2_subdev_enum_strm_fmts( void *img_src, u32 index, struct cif_isp10_strm_fmt_desc *strm_fmt_desc) { int ret; struct v4l2_subdev *subdev = img_src; struct v4l2_subdev_frame_interval_enum fie = {.index = index}; struct pltfrm_cam_defrect defrect; v4l2_std_id std; ret = v4l2_subdev_call(subdev, video, querystd, &std); if (!IS_ERR_VALUE(ret)) strm_fmt_desc->std_id = std; else strm_fmt_desc->std_id = 0; ret = v4l2_subdev_call(subdev, pad, enum_frame_interval, NULL, &fie); if (!IS_ERR_VALUE(ret)) { strm_fmt_desc->discrete_intrvl = true; strm_fmt_desc->min_intrvl.numerator = fie.interval.numerator; strm_fmt_desc->min_intrvl.denominator = fie.interval.denominator; strm_fmt_desc->discrete_frmsize = true; strm_fmt_desc->min_frmsize.width = fie.width; strm_fmt_desc->min_frmsize.height = fie.height; strm_fmt_desc->pix_fmt = img_src_v4l2_subdev_pix_fmt2cif_isp10_pix_fmt( fie.code); defrect.width = fie.width; defrect.height = fie.height; memset(&defrect.defrect, 0x00, sizeof(defrect.defrect)); v4l2_subdev_call(subdev, core, ioctl, PLTFRM_CIFCAM_G_DEFRECT, (void *)&defrect); if ((defrect.defrect.width == 0) || (defrect.defrect.height == 0)) { strm_fmt_desc->defrect.left = 0; strm_fmt_desc->defrect.top = 0; strm_fmt_desc->defrect.width = fie.width; strm_fmt_desc->defrect.height = fie.height; } else { strm_fmt_desc->defrect = defrect.defrect; } } return ret; } int cif_isp10_img_src_v4l2_subdev_s_strm_fmt( void *img_src, struct cif_isp10_strm_fmt *strm_fmt) { int ret = 0; struct v4l2_subdev *subdev = img_src; struct v4l2_subdev_format format; struct v4l2_subdev_frame_interval intrvl; format.which = V4L2_SUBDEV_FORMAT_ACTIVE; format.format.code = cif_isp10_pix_fmt2img_src_v4l2_subdev_pix_fmt( strm_fmt->frm_fmt.pix_fmt); format.format.width = strm_fmt->frm_fmt.width; format.format.height = strm_fmt->frm_fmt.height; ret = v4l2_subdev_call(subdev, pad, set_fmt, NULL, &format); if (IS_ERR_VALUE(ret)) goto err; intrvl.interval.numerator = strm_fmt->frm_intrvl.numerator; intrvl.interval.denominator = strm_fmt->frm_intrvl.denominator; ret = v4l2_subdev_call(subdev, video, s_frame_interval, &intrvl); if (IS_ERR_VALUE(ret)) goto err; return 0; err: pr_err("img_src.%s ERR: failed with error %d\n", __func__, ret); return ret; } int cif_isp10_img_src_v4l2_subdev_g_ctrl( void *img_src, int id, int *val) { struct v4l2_control ctrl; int ret; struct v4l2_subdev *subdev = img_src; ctrl.id = cif_isp10_v4l2_cid2v4l2_cid(id); if (IS_ERR_VALUE(ctrl.id)) return (int)ctrl.id; ret = v4l2_subdev_call(subdev, core, g_ctrl, &ctrl); if (!IS_ERR_VALUE(ret)) { if (id == CIF_ISP10_CID_FLASH_MODE) { if (ctrl.value == V4L2_FLASH_LED_MODE_NONE) { ctrl.value = CIF_ISP10_FLASH_MODE_OFF; } else if (ctrl.value == V4L2_FLASH_LED_MODE_FLASH) { ctrl.value = CIF_ISP10_FLASH_MODE_FLASH; } else if (ctrl.value == V4L2_FLASH_LED_MODE_TORCH) { ctrl.value = CIF_ISP10_FLASH_MODE_TORCH; } else { cif_isp10_pltfrm_pr_err(NULL, "unknown/unsupported value %d for control ID 0x%x\n", ctrl.value, id); return -EINVAL; } } *val = ctrl.value; } else { cif_isp10_pltfrm_pr_err(NULL, "subdevcall got err: %d\n", ret); } return ret; } int cif_isp10_img_src_v4l2_subdev_s_ctrl( void *img_src, int id, int val) { struct v4l2_control ctrl; struct v4l2_subdev *subdev = img_src; ctrl.value = val; ctrl.id = cif_isp10_v4l2_cid2v4l2_cid(id); if (IS_ERR_VALUE(ctrl.id)) { return (int)ctrl.id; } else if (id == CIF_ISP10_CID_FLASH_MODE) { if (val == CIF_ISP10_FLASH_MODE_OFF) { ctrl.value = V4L2_FLASH_LED_MODE_NONE; } else if (val == CIF_ISP10_FLASH_MODE_FLASH) { ctrl.value = V4L2_FLASH_LED_MODE_FLASH; } else if (val == CIF_ISP10_FLASH_MODE_TORCH) { ctrl.value = V4L2_FLASH_LED_MODE_TORCH; } else { cif_isp10_pltfrm_pr_err(NULL, "unknown/unsupported value %d for control ID %d\n", val, id); return -EINVAL; } } return v4l2_subdev_call(subdev, core, s_ctrl, &ctrl); } const char *cif_isp10_img_src_v4l2_subdev_g_name( void *img_src) { struct v4l2_subdev *subdev = img_src; return dev_driver_string(subdev->dev); } int cif_isp10_img_src_v4l2_subdev_s_ext_ctrls( void *img_src, struct cif_isp10_img_src_ext_ctrl *ctrl) { struct v4l2_ext_controls ctrls; struct v4l2_ext_control *controls; int i; int ret; struct v4l2_subdev *subdev = img_src; if (ctrl->cnt == 0) return -EINVAL; controls = kmalloc_array(ctrl->cnt, sizeof(struct v4l2_ext_control), GFP_KERNEL); if (!controls) return -ENOMEM; for (i = 0; i < ctrl->cnt; i++) { controls[i].id = ctrl->ctrls[i].id; controls[i].value = ctrl->ctrls[i].val; } ctrls.count = ctrl->cnt; ctrls.controls = controls; /* * current kernel version don't define * this member for struct v4l2_ext_control. */ /* ctrls.ctrl_class = ctrl->class; */ ctrls.reserved[0] = 0; ctrls.reserved[1] = 0; ret = v4l2_subdev_call(subdev, core, s_ext_ctrls, &ctrls); kfree(controls); return ret; } long cif_isp10_img_src_v4l2_subdev_ioctl( void *img_src, unsigned int cmd, void *arg) { struct v4l2_subdev *subdev = img_src; long ret = -EINVAL; switch (cmd) { case RK_VIDIOC_SENSOR_MODE_DATA: case RK_VIDIOC_CAMERA_MODULEINFO: case RK_VIDIOC_SENSOR_CONFIGINFO: case RK_VIDIOC_SENSOR_REG_ACCESS: case PLTFRM_CIFCAM_G_ITF_CFG: case PLTFRM_CIFCAM_G_DEFRECT: case PLTFRM_CIFCAM_ATTACH: case PLTFRM_CIFCAM_SET_VCM_POS: case PLTFRM_CIFCAM_GET_VCM_POS: case PLTFRM_CIFCAM_GET_VCM_MOVE_RES: ret = v4l2_subdev_call(subdev, core, ioctl, cmd, arg); break; default: break; } if (IS_ERR_VALUE(ret) && cmd != PLTFRM_CIFCAM_GET_VCM_MOVE_RES) pr_err("img_src.%s subdev call(cmd: 0x%x) failed with error %ld\n", __func__, cmd, ret); return ret; } int cif_isp10_img_src_v4l2_subdev_s_frame_interval( void *img_src, struct cif_isp10_frm_intrvl *frm_intrvl) { int ret = 0; struct v4l2_subdev *subdev = img_src; struct v4l2_subdev_frame_interval interval; interval.interval.numerator = frm_intrvl->numerator; interval.interval.denominator = frm_intrvl->denominator; ret = v4l2_subdev_call(subdev, video, s_frame_interval, &interval); if (IS_ERR_VALUE(ret)) goto err; return 0; err: pr_err("img_src.%s ERR: failed with error %d\n", __func__, ret); return ret; } int cif_isp10_img_src_v4l2_subdev_g_frame_interval( void *img_src, struct cif_isp10_frm_intrvl *frm_intrvl) { int ret = 0; struct v4l2_subdev *subdev = img_src; struct v4l2_subdev_frame_interval interval; interval.interval.numerator = 0; interval.interval.denominator = 0; ret = v4l2_subdev_call(subdev, video, g_frame_interval, &interval); if (IS_ERR_VALUE(ret)) goto err; frm_intrvl->denominator = interval.interval.denominator; frm_intrvl->numerator = interval.interval.numerator; return 0; err: pr_err("img_src.%s ERR: failed with error %d\n", __func__, ret); return ret; } int cif_isp10_img_src_v4l2_subdev_enum_frame_size( void *img_src, struct v4l2_subdev_frame_size_enum *fse) { struct v4l2_subdev *subdev = img_src; return v4l2_subdev_call(subdev, pad, enum_frame_size, NULL, fse); }