summaryrefslogtreecommitdiff
path: root/linux/drivers/media/video/sh_mobile_ceu_camera.c
diff options
context:
space:
mode:
Diffstat (limited to 'linux/drivers/media/video/sh_mobile_ceu_camera.c')
-rw-r--r--linux/drivers/media/video/sh_mobile_ceu_camera.c60
1 files changed, 50 insertions, 10 deletions
diff --git a/linux/drivers/media/video/sh_mobile_ceu_camera.c b/linux/drivers/media/video/sh_mobile_ceu_camera.c
index ae98eaf5f..29ff02802 100644
--- a/linux/drivers/media/video/sh_mobile_ceu_camera.c
+++ b/linux/drivers/media/video/sh_mobile_ceu_camera.c
@@ -102,6 +102,30 @@ struct sh_mobile_ceu_dev {
const struct soc_camera_data_format *camera_fmt;
};
+static unsigned long make_bus_param(struct sh_mobile_ceu_dev *pcdev)
+{
+ unsigned long flags;
+
+ flags = SOCAM_MASTER |
+ SOCAM_PCLK_SAMPLE_RISING |
+ SOCAM_HSYNC_ACTIVE_HIGH |
+ SOCAM_HSYNC_ACTIVE_LOW |
+ SOCAM_VSYNC_ACTIVE_HIGH |
+ SOCAM_VSYNC_ACTIVE_LOW |
+ SOCAM_DATA_ACTIVE_HIGH;
+
+ if (pcdev->pdata->flags & SH_CEU_FLAG_USE_8BIT_BUS)
+ flags |= SOCAM_DATAWIDTH_8;
+
+ if (pcdev->pdata->flags & SH_CEU_FLAG_USE_16BIT_BUS)
+ flags |= SOCAM_DATAWIDTH_16;
+
+ if (flags & SOCAM_DATAWIDTH_MASK)
+ return flags;
+
+ return 0;
+}
+
static void ceu_write(struct sh_mobile_ceu_dev *priv,
unsigned long reg_offs, u32 data)
{
@@ -397,7 +421,7 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd,
camera_flags = icd->ops->query_bus_param(icd);
common_flags = soc_camera_bus_param_compatible(camera_flags,
- pcdev->pdata->flags);
+ make_bus_param(pcdev));
if (!common_flags)
return -EINVAL;
@@ -518,7 +542,7 @@ static int sh_mobile_ceu_try_bus_param(struct soc_camera_device *icd)
camera_flags = icd->ops->query_bus_param(icd);
common_flags = soc_camera_bus_param_compatible(camera_flags,
- pcdev->pdata->flags);
+ make_bus_param(pcdev));
if (!common_flags)
return -EINVAL;
@@ -563,11 +587,29 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, int idx,
if (ret < 0)
return 0;
+ /* Beginning of a pass */
+ if (!idx)
+ icd->host_priv = NULL;
+
switch (icd->formats[idx].fourcc) {
case V4L2_PIX_FMT_UYVY:
case V4L2_PIX_FMT_VYUY:
case V4L2_PIX_FMT_YUYV:
case V4L2_PIX_FMT_YVYU:
+ if (icd->host_priv)
+ goto add_single_format;
+
+ /*
+ * Our case is simple so far: for any of the above four camera
+ * formats we add all our four synthesized NV* formats, so,
+ * just marking the device with a single flag suffices. If
+ * the format generation rules are more complex, you would have
+ * to actually hang your already added / counted formats onto
+ * the host_priv pointer and check whether the format you're
+ * going to add now is already there.
+ */
+ icd->host_priv = (void *)sh_mobile_ceu_formats;
+
n = ARRAY_SIZE(sh_mobile_ceu_formats);
formats += n;
for (k = 0; xlate && k < n; k++) {
@@ -580,6 +622,7 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, int idx,
icd->formats[idx].name);
}
default:
+add_single_format:
/* Generic pass-through */
formats++;
if (xlate) {
@@ -604,21 +647,18 @@ static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd,
const struct soc_camera_format_xlate *xlate;
int ret;
+ if (!pixfmt)
+ return icd->ops->set_fmt(icd, pixfmt, rect);
+
xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
if (!xlate) {
dev_warn(&ici->dev, "Format %x not found\n", pixfmt);
return -EINVAL;
}
- switch (pixfmt) {
- case 0: /* Only geometry change */
- ret = icd->ops->set_fmt(icd, pixfmt, rect);
- break;
- default:
- ret = icd->ops->set_fmt(icd, xlate->cam_fmt->fourcc, rect);
- }
+ ret = icd->ops->set_fmt(icd, xlate->cam_fmt->fourcc, rect);
- if (pixfmt && !ret) {
+ if (!ret) {
icd->buswidth = xlate->buswidth;
icd->current_fmt = xlate->host_fmt;
pcdev->camera_fmt = xlate->cam_fmt;