static int omap1_cam_get_formats(struct soc_camera_device *icd, unsigned int idx, struct soc_camera_format_xlate *xlate) { struct v4l2_subdev *sd = soc_camera_to_subdev(icd); struct device *dev = icd->dev.parent; int formats = 0, ret; enum v4l2_mbus_pixelcode code; const struct soc_mbus_pixelfmt *fmt; ret = v4l2_subdev_call(sd, video, enum_mbus_fmt, idx, &code); if (ret < 0) /* No more formats */ return 0; fmt = soc_mbus_get_fmtdesc(code); if (!fmt) { dev_warn(dev, "%s: unsupported format code #%d: %d\n", __func__, idx, code); return 0; } /* Check support for the requested bits-per-sample */ if (fmt->bits_per_sample != 8) return 0; switch (code) { case V4L2_MBUS_FMT_YUYV8_2X8: case V4L2_MBUS_FMT_YVYU8_2X8: case V4L2_MBUS_FMT_UYVY8_2X8: case V4L2_MBUS_FMT_VYUY8_2X8: case V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE: case V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE: case V4L2_MBUS_FMT_RGB565_2X8_BE: case V4L2_MBUS_FMT_RGB565_2X8_LE: formats++; if (xlate) { xlate->host_fmt = soc_mbus_find_fmtdesc(code, omap1_cam_formats, ARRAY_SIZE(omap1_cam_formats)); xlate->code = code; xlate++; dev_dbg(dev, "%s: providing format %s as byte swapped code #%d\n", __func__, xlate->host_fmt->name, code); } default: if (xlate) dev_dbg(dev, "%s: providing format %s in pass-through mode\n", __func__, fmt->name); } formats++; if (xlate) { xlate->host_fmt = fmt; xlate->code = code; xlate++; } return formats; }
static void configure_geometry(struct mx3_camera_dev *mx3_cam, unsigned int width, unsigned int height, enum v4l2_mbus_pixelcode code) { u32 ctrl, width_field, height_field; const struct soc_mbus_pixelfmt *fmt; fmt = soc_mbus_get_fmtdesc(code); BUG_ON(!fmt); if (fourcc_to_ipu_pix(fmt->fourcc) == IPU_PIX_FMT_GENERIC) { /* * As the CSI will be configured to output BAYER, here * the width parameter count the number of samples to * capture to complete the whole image width. */ width *= soc_mbus_samples_per_pixel(fmt); BUG_ON(width < 0); } /* Setup frame size - this cannot be changed on-the-fly... */ width_field = width - 1; height_field = height - 1; csi_reg_write(mx3_cam, width_field | (height_field << 16), CSI_SENS_FRM_SIZE); csi_reg_write(mx3_cam, width_field << 16, CSI_FLASH_STROBE_1); csi_reg_write(mx3_cam, (height_field << 16) | 0x22, CSI_FLASH_STROBE_2); csi_reg_write(mx3_cam, width_field | (height_field << 16), CSI_ACT_FRM_SIZE); /* ...and position */ ctrl = csi_reg_read(mx3_cam, CSI_OUT_FRM_CTRL) & 0xffff0000; /* Sensor does the cropping */ csi_reg_write(mx3_cam, ctrl | 0 | (0 << 8), CSI_OUT_FRM_CTRL); }
/** * @brief: getting image format information * * @author: caolianming * @date: 2014-01-06 * @param [in] *icd: soc_camera_device information structure, * akcamera depends on the soc driver. * @param [in] *f: image format */ static int ak_camera_get_formats(struct soc_camera_device *icd, unsigned int idx, struct soc_camera_format_xlate *xlate) { struct v4l2_subdev *sd = soc_camera_to_subdev(icd); struct device *dev = icd->parent; struct soc_camera_host *ici = to_soc_camera_host(dev); struct ak_camera_dev *pcdev = ici->priv; int ret, formats = 0; enum v4l2_mbus_pixelcode code; const struct soc_mbus_pixelfmt *fmt; CAMDBG("entry %s\n", __func__); ret = v4l2_subdev_call(sd, video, enum_mbus_fmt, idx, &code); if (ret < 0) /* No more formats */ return 0; /* * @Note: ISP only support yuv420 output and jpeg out. * FIXME1: We miss jpeg here. * FIXME2: the output squence of YUV is actually UYVY. */ fmt = soc_mbus_get_fmtdesc(V4L2_MBUS_FMT_YUYV8_2X8); if (!fmt) { dev_warn(dev, "unsupported format code #%u: %d\n", idx, code); return 0; } CAMDBG("get format %s code=%d from sensor\n", fmt->name, code); /* Generic pass-through */ formats++; if (xlate) { xlate->host_fmt = fmt; xlate->code = code; xlate++; /* * @decide the default working mode of isp * @prefer RGB mode */ if (code < V4L2_MBUS_FMT_Y8_1X8) { pcdev->def_mode = ISP_RGB_VIDEO_OUT; //pcdev->def_mode = ISP_RGB_OUT; } if ((pcdev->def_mode != ISP_RGB_VIDEO_OUT) && (pcdev->def_mode != ISP_RGB_OUT)) { pcdev->def_mode = ISP_YUV_VIDEO_BYPASS; //pcdev->def_mode = ISP_YUV_BYPASS; } pcdev->isp.cur_mode = pcdev->def_mode; update_cur_mode_class(&pcdev->isp); dev_dbg(dev, "Providing format %s in pass-through mode\n", fmt->name); } return formats; }
static int mx3_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) { struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); struct mx3_camera_dev *mx3_cam = ici->priv; unsigned long bus_flags, camera_flags, common_flags; u32 dw, sens_conf; const struct soc_mbus_pixelfmt *fmt; int buswidth; int ret; const struct soc_camera_format_xlate *xlate; struct device *dev = icd->dev.parent; fmt = soc_mbus_get_fmtdesc(icd->current_fmt->code); if (!fmt) return -EINVAL; buswidth = fmt->bits_per_sample; ret = test_platform_param(mx3_cam, buswidth, &bus_flags); xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); if (!xlate) { dev_warn(dev, "Format %x not found\n", pixfmt); return -EINVAL; } dev_dbg(dev, "requested bus width %d bit: %d\n", buswidth, ret); if (ret < 0) return ret; camera_flags = icd->ops->query_bus_param(icd); common_flags = soc_camera_bus_param_compatible(camera_flags, bus_flags); dev_dbg(dev, "Flags cam: 0x%lx host: 0x%lx common: 0x%lx\n", camera_flags, bus_flags, common_flags); if (!common_flags) { dev_dbg(dev, "no common flags"); return -EINVAL; } /* Make choices, based on platform preferences */ if ((common_flags & SOCAM_HSYNC_ACTIVE_HIGH) && (common_flags & SOCAM_HSYNC_ACTIVE_LOW)) { if (mx3_cam->platform_flags & MX3_CAMERA_HSP) common_flags &= ~SOCAM_HSYNC_ACTIVE_HIGH; else common_flags &= ~SOCAM_HSYNC_ACTIVE_LOW; } if ((common_flags & SOCAM_VSYNC_ACTIVE_HIGH) && (common_flags & SOCAM_VSYNC_ACTIVE_LOW)) { if (mx3_cam->platform_flags & MX3_CAMERA_VSP) common_flags &= ~SOCAM_VSYNC_ACTIVE_HIGH; else common_flags &= ~SOCAM_VSYNC_ACTIVE_LOW; } if ((common_flags & SOCAM_DATA_ACTIVE_HIGH) && (common_flags & SOCAM_DATA_ACTIVE_LOW)) { if (mx3_cam->platform_flags & MX3_CAMERA_DP) common_flags &= ~SOCAM_DATA_ACTIVE_HIGH; else common_flags &= ~SOCAM_DATA_ACTIVE_LOW; } if ((common_flags & SOCAM_PCLK_SAMPLE_RISING) && (common_flags & SOCAM_PCLK_SAMPLE_FALLING)) { if (mx3_cam->platform_flags & MX3_CAMERA_PCP) common_flags &= ~SOCAM_PCLK_SAMPLE_RISING; else common_flags &= ~SOCAM_PCLK_SAMPLE_FALLING; } /* * Make the camera work in widest common mode, we'll take care of * the rest */ if (common_flags & SOCAM_DATAWIDTH_15) common_flags = (common_flags & ~SOCAM_DATAWIDTH_MASK) | SOCAM_DATAWIDTH_15; else if (common_flags & SOCAM_DATAWIDTH_10) common_flags = (common_flags & ~SOCAM_DATAWIDTH_MASK) | SOCAM_DATAWIDTH_10; else if (common_flags & SOCAM_DATAWIDTH_8) common_flags = (common_flags & ~SOCAM_DATAWIDTH_MASK) | SOCAM_DATAWIDTH_8; else common_flags = (common_flags & ~SOCAM_DATAWIDTH_MASK) | SOCAM_DATAWIDTH_4; ret = icd->ops->set_bus_param(icd, common_flags); if (ret < 0) { dev_dbg(dev, "camera set_bus_param(%lx) returned %d\n", common_flags, ret); return ret; } /* * So far only gated clock mode is supported. Add a line * (3 << CSI_SENS_CONF_SENS_PRTCL_SHIFT) | * below and select the required mode when supporting other * synchronisation protocols. */ sens_conf = csi_reg_read(mx3_cam, CSI_SENS_CONF) & ~((1 << CSI_SENS_CONF_VSYNC_POL_SHIFT) | (1 << CSI_SENS_CONF_HSYNC_POL_SHIFT) | (1 << CSI_SENS_CONF_DATA_POL_SHIFT) | (1 << CSI_SENS_CONF_PIX_CLK_POL_SHIFT) | (3 << CSI_SENS_CONF_DATA_FMT_SHIFT) | (3 << CSI_SENS_CONF_DATA_WIDTH_SHIFT)); /* TODO: Support RGB and YUV formats */ /* This has been set in mx3_camera_activate(), but we clear it above */ sens_conf |= CSI_SENS_CONF_DATA_FMT_BAYER; if (common_flags & SOCAM_PCLK_SAMPLE_FALLING) sens_conf |= 1 << CSI_SENS_CONF_PIX_CLK_POL_SHIFT; if (common_flags & SOCAM_HSYNC_ACTIVE_LOW) sens_conf |= 1 << CSI_SENS_CONF_HSYNC_POL_SHIFT; if (common_flags & SOCAM_VSYNC_ACTIVE_LOW) sens_conf |= 1 << CSI_SENS_CONF_VSYNC_POL_SHIFT; if (common_flags & SOCAM_DATA_ACTIVE_LOW) sens_conf |= 1 << CSI_SENS_CONF_DATA_POL_SHIFT; /* Just do what we're asked to do */ switch (xlate->host_fmt->bits_per_sample) { case 4: dw = 0 << CSI_SENS_CONF_DATA_WIDTH_SHIFT; break; case 8: dw = 1 << CSI_SENS_CONF_DATA_WIDTH_SHIFT; break; case 10: dw = 2 << CSI_SENS_CONF_DATA_WIDTH_SHIFT; break; default: /* * Actually it can only be 15 now, default is just to silence * compiler warnings */ case 15: dw = 3 << CSI_SENS_CONF_DATA_WIDTH_SHIFT; } csi_reg_write(mx3_cam, sens_conf | dw, CSI_SENS_CONF); dev_dbg(dev, "Set SENS_CONF to %x\n", sens_conf | dw); return 0; }
static int mx3_camera_get_formats(struct soc_camera_device *icd, unsigned int idx, struct soc_camera_format_xlate *xlate) { struct v4l2_subdev *sd = soc_camera_to_subdev(icd); struct device *dev = icd->dev.parent; int formats = 0, ret; enum v4l2_mbus_pixelcode code; const struct soc_mbus_pixelfmt *fmt; ret = v4l2_subdev_call(sd, video, enum_mbus_fmt, idx, &code); if (ret < 0) /* No more formats */ return 0; fmt = soc_mbus_get_fmtdesc(code); if (!fmt) { dev_err(icd->dev.parent, "Invalid format code #%u: %d\n", idx, code); return 0; } /* This also checks support for the requested bits-per-sample */ ret = mx3_camera_try_bus_param(icd, fmt->bits_per_sample); if (ret < 0) return 0; switch (code) { case V4L2_MBUS_FMT_SBGGR10_1X10: formats++; if (xlate) { xlate->host_fmt = &mx3_camera_formats[0]; xlate->code = code; xlate++; dev_dbg(dev, "Providing format %s using code %d\n", mx3_camera_formats[0].name, code); } break; case V4L2_MBUS_FMT_Y10_1X10: formats++; if (xlate) { xlate->host_fmt = &mx3_camera_formats[1]; xlate->code = code; xlate++; dev_dbg(dev, "Providing format %s using code %d\n", mx3_camera_formats[1].name, code); } break; default: if (!mx3_camera_packing_supported(fmt)) return 0; } /* Generic pass-through */ formats++; if (xlate) { xlate->host_fmt = fmt; xlate->code = code; dev_dbg(dev, "Providing format %c%c%c%c in pass-through mode\n", (fmt->fourcc >> (0*8)) & 0xFF, (fmt->fourcc >> (1*8)) & 0xFF, (fmt->fourcc >> (2*8)) & 0xFF, (fmt->fourcc >> (3*8)) & 0xFF); xlate++; } return formats; }