summaryrefslogtreecommitdiff
path: root/linux
diff options
context:
space:
mode:
Diffstat (limited to 'linux')
-rw-r--r--linux/drivers/media/video/mt9m001.c14
-rw-r--r--linux/drivers/media/video/mt9m111.c12
-rw-r--r--linux/drivers/media/video/mt9v022.c14
-rw-r--r--linux/drivers/media/video/ov772x.c97
-rw-r--r--linux/drivers/media/video/pxa_camera.c203
-rw-r--r--linux/drivers/media/video/sh_mobile_ceu_camera.c52
-rw-r--r--linux/drivers/media/video/soc_camera.c166
-rw-r--r--linux/drivers/media/video/soc_camera_platform.c12
-rw-r--r--linux/include/media/soc_camera.h40
9 files changed, 441 insertions, 169 deletions
diff --git a/linux/drivers/media/video/mt9m001.c b/linux/drivers/media/video/mt9m001.c
index 228183c54..edacba723 100644
--- a/linux/drivers/media/video/mt9m001.c
+++ b/linux/drivers/media/video/mt9m001.c
@@ -285,8 +285,8 @@ static unsigned long mt9m001_query_bus_param(struct soc_camera_device *icd)
width_flag;
}
-static int mt9m001_set_fmt_cap(struct soc_camera_device *icd,
- __u32 pixfmt, struct v4l2_rect *rect)
+static int mt9m001_set_fmt(struct soc_camera_device *icd,
+ __u32 pixfmt, struct v4l2_rect *rect)
{
struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
int ret;
@@ -298,7 +298,7 @@ static int mt9m001_set_fmt_cap(struct soc_camera_device *icd,
ret = reg_write(icd, MT9M001_VERTICAL_BLANKING, vblank);
/* The caller provides a supported format, as verified per
- * call to icd->try_fmt_cap() */
+ * call to icd->try_fmt() */
if (!ret)
ret = reg_write(icd, MT9M001_COLUMN_START, rect->left);
if (!ret)
@@ -325,8 +325,8 @@ static int mt9m001_set_fmt_cap(struct soc_camera_device *icd,
return ret;
}
-static int mt9m001_try_fmt_cap(struct soc_camera_device *icd,
- struct v4l2_format *f)
+static int mt9m001_try_fmt(struct soc_camera_device *icd,
+ struct v4l2_format *f)
{
if (f->fmt.pix.height < 32 + icd->y_skip_top)
f->fmt.pix.height = 32 + icd->y_skip_top;
@@ -447,8 +447,8 @@ static struct soc_camera_ops mt9m001_ops = {
.release = mt9m001_release,
.start_capture = mt9m001_start_capture,
.stop_capture = mt9m001_stop_capture,
- .set_fmt_cap = mt9m001_set_fmt_cap,
- .try_fmt_cap = mt9m001_try_fmt_cap,
+ .set_fmt = mt9m001_set_fmt,
+ .try_fmt = mt9m001_try_fmt,
.set_bus_param = mt9m001_set_bus_param,
.query_bus_param = mt9m001_query_bus_param,
.controls = mt9m001_controls,
diff --git a/linux/drivers/media/video/mt9m111.c b/linux/drivers/media/video/mt9m111.c
index ceff40edc..1fde94514 100644
--- a/linux/drivers/media/video/mt9m111.c
+++ b/linux/drivers/media/video/mt9m111.c
@@ -452,8 +452,8 @@ static int mt9m111_set_pixfmt(struct soc_camera_device *icd, u32 pixfmt)
return ret;
}
-static int mt9m111_set_fmt_cap(struct soc_camera_device *icd,
- __u32 pixfmt, struct v4l2_rect *rect)
+static int mt9m111_set_fmt(struct soc_camera_device *icd,
+ __u32 pixfmt, struct v4l2_rect *rect)
{
struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
int ret;
@@ -473,8 +473,8 @@ static int mt9m111_set_fmt_cap(struct soc_camera_device *icd,
return ret;
}
-static int mt9m111_try_fmt_cap(struct soc_camera_device *icd,
- struct v4l2_format *f)
+static int mt9m111_try_fmt(struct soc_camera_device *icd,
+ struct v4l2_format *f)
{
if (f->fmt.pix.height > MT9M111_MAX_HEIGHT)
f->fmt.pix.height = MT9M111_MAX_HEIGHT;
@@ -597,8 +597,8 @@ static struct soc_camera_ops mt9m111_ops = {
.release = mt9m111_release,
.start_capture = mt9m111_start_capture,
.stop_capture = mt9m111_stop_capture,
- .set_fmt_cap = mt9m111_set_fmt_cap,
- .try_fmt_cap = mt9m111_try_fmt_cap,
+ .set_fmt = mt9m111_set_fmt,
+ .try_fmt = mt9m111_try_fmt,
.query_bus_param = mt9m111_query_bus_param,
.set_bus_param = mt9m111_set_bus_param,
.controls = mt9m111_controls,
diff --git a/linux/drivers/media/video/mt9v022.c b/linux/drivers/media/video/mt9v022.c
index bea695a2c..1ca28c087 100644
--- a/linux/drivers/media/video/mt9v022.c
+++ b/linux/drivers/media/video/mt9v022.c
@@ -337,14 +337,14 @@ static unsigned long mt9v022_query_bus_param(struct soc_camera_device *icd)
width_flag;
}
-static int mt9v022_set_fmt_cap(struct soc_camera_device *icd,
- __u32 pixfmt, struct v4l2_rect *rect)
+static int mt9v022_set_fmt(struct soc_camera_device *icd,
+ __u32 pixfmt, struct v4l2_rect *rect)
{
struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
int ret;
/* The caller provides a supported format, as verified per call to
- * icd->try_fmt_cap(), datawidth is from our supported format list */
+ * icd->try_fmt(), datawidth is from our supported format list */
switch (pixfmt) {
case V4L2_PIX_FMT_GREY:
case V4L2_PIX_FMT_Y16:
@@ -400,8 +400,8 @@ static int mt9v022_set_fmt_cap(struct soc_camera_device *icd,
return 0;
}
-static int mt9v022_try_fmt_cap(struct soc_camera_device *icd,
- struct v4l2_format *f)
+static int mt9v022_try_fmt(struct soc_camera_device *icd,
+ struct v4l2_format *f)
{
if (f->fmt.pix.height < 32 + icd->y_skip_top)
f->fmt.pix.height = 32 + icd->y_skip_top;
@@ -538,8 +538,8 @@ static struct soc_camera_ops mt9v022_ops = {
.release = mt9v022_release,
.start_capture = mt9v022_start_capture,
.stop_capture = mt9v022_stop_capture,
- .set_fmt_cap = mt9v022_set_fmt_cap,
- .try_fmt_cap = mt9v022_try_fmt_cap,
+ .set_fmt = mt9v022_set_fmt,
+ .try_fmt = mt9v022_try_fmt,
.set_bus_param = mt9v022_set_bus_param,
.query_bus_param = mt9v022_query_bus_param,
.controls = mt9v022_controls,
diff --git a/linux/drivers/media/video/ov772x.c b/linux/drivers/media/video/ov772x.c
index 2ddc2ab70..c023bbc84 100644
--- a/linux/drivers/media/video/ov772x.c
+++ b/linux/drivers/media/video/ov772x.c
@@ -112,34 +112,34 @@
#define AREF7 0x55 /* Analog reference control */
#define UFIX 0x60 /* U channel fixed value output */
#define VFIX 0x61 /* V channel fixed value output */
-#define AW_BB_BLK 0x62 /* AWB option for advanced AWB */
-#define AW_B_CTRL0 0x63 /* AWB control byte 0 */
+#define AWBB_BLK 0x62 /* AWB option for advanced AWB */
+#define AWB_CTRL0 0x63 /* AWB control byte 0 */
#define DSP_CTRL1 0x64 /* DSP control byte 1 */
#define DSP_CTRL2 0x65 /* DSP control byte 2 */
#define DSP_CTRL3 0x66 /* DSP control byte 3 */
#define DSP_CTRL4 0x67 /* DSP control byte 4 */
-#define AW_B_BIAS 0x68 /* AWB BLC level clip */
-#define AW_BCTRL1 0x69 /* AWB control 1 */
-#define AW_BCTRL2 0x6A /* AWB control 2 */
-#define AW_BCTRL3 0x6B /* AWB control 3 */
-#define AW_BCTRL4 0x6C /* AWB control 4 */
-#define AW_BCTRL5 0x6D /* AWB control 5 */
-#define AW_BCTRL6 0x6E /* AWB control 6 */
-#define AW_BCTRL7 0x6F /* AWB control 7 */
-#define AW_BCTRL8 0x70 /* AWB control 8 */
-#define AW_BCTRL9 0x71 /* AWB control 9 */
-#define AW_BCTRL10 0x72 /* AWB control 10 */
-#define AW_BCTRL11 0x73 /* AWB control 11 */
-#define AW_BCTRL12 0x74 /* AWB control 12 */
-#define AW_BCTRL13 0x75 /* AWB control 13 */
-#define AW_BCTRL14 0x76 /* AWB control 14 */
-#define AW_BCTRL15 0x77 /* AWB control 15 */
-#define AW_BCTRL16 0x78 /* AWB control 16 */
-#define AW_BCTRL17 0x79 /* AWB control 17 */
-#define AW_BCTRL18 0x7A /* AWB control 18 */
-#define AW_BCTRL19 0x7B /* AWB control 19 */
-#define AW_BCTRL20 0x7C /* AWB control 20 */
-#define AW_BCTRL21 0x7D /* AWB control 21 */
+#define AWB_BIAS 0x68 /* AWB BLC level clip */
+#define AWB_CTRL1 0x69 /* AWB control 1 */
+#define AWB_CTRL2 0x6A /* AWB control 2 */
+#define AWB_CTRL3 0x6B /* AWB control 3 */
+#define AWB_CTRL4 0x6C /* AWB control 4 */
+#define AWB_CTRL5 0x6D /* AWB control 5 */
+#define AWB_CTRL6 0x6E /* AWB control 6 */
+#define AWB_CTRL7 0x6F /* AWB control 7 */
+#define AWB_CTRL8 0x70 /* AWB control 8 */
+#define AWB_CTRL9 0x71 /* AWB control 9 */
+#define AWB_CTRL10 0x72 /* AWB control 10 */
+#define AWB_CTRL11 0x73 /* AWB control 11 */
+#define AWB_CTRL12 0x74 /* AWB control 12 */
+#define AWB_CTRL13 0x75 /* AWB control 13 */
+#define AWB_CTRL14 0x76 /* AWB control 14 */
+#define AWB_CTRL15 0x77 /* AWB control 15 */
+#define AWB_CTRL16 0x78 /* AWB control 16 */
+#define AWB_CTRL17 0x79 /* AWB control 17 */
+#define AWB_CTRL18 0x7A /* AWB control 18 */
+#define AWB_CTRL19 0x7B /* AWB control 19 */
+#define AWB_CTRL20 0x7C /* AWB control 20 */
+#define AWB_CTRL21 0x7D /* AWB control 21 */
#define GAM1 0x7E /* Gamma Curve 1st segment input end point */
#define GAM2 0x7F /* Gamma Curve 2nd segment input end point */
#define GAM3 0x80 /* Gamma Curve 3rd segment input end point */
@@ -593,12 +593,30 @@ static int ov772x_reset(struct i2c_client *client)
static int ov772x_init(struct soc_camera_device *icd)
{
- return 0;
+ struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
+ int ret = 0;
+
+ if (priv->info->link.power) {
+ ret = priv->info->link.power(&priv->client->dev, 1);
+ if (ret < 0)
+ return ret;
+ }
+
+ if (priv->info->link.reset)
+ ret = priv->info->link.reset(&priv->client->dev);
+
+ return ret;
}
static int ov772x_release(struct soc_camera_device *icd)
{
- return 0;
+ struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
+ int ret = 0;
+
+ if (priv->info->link.power)
+ ret = priv->info->link.power(&priv->client->dev, 0);
+
+ return ret;
}
static int ov772x_start_capture(struct soc_camera_device *icd)
@@ -737,9 +755,9 @@ static int ov772x_set_register(struct soc_camera_device *icd,
}
#endif
-static int ov772x_set_fmt_cap(struct soc_camera_device *icd,
- __u32 pixfmt,
- struct v4l2_rect *rect)
+static int ov772x_set_fmt(struct soc_camera_device *icd,
+ __u32 pixfmt,
+ struct v4l2_rect *rect)
{
struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
int ret = -EINVAL;
@@ -760,8 +778,8 @@ static int ov772x_set_fmt_cap(struct soc_camera_device *icd,
return ret;
}
-static int ov772x_try_fmt_cap(struct soc_camera_device *icd,
- struct v4l2_format *f)
+static int ov772x_try_fmt(struct soc_camera_device *icd,
+ struct v4l2_format *f)
{
struct v4l2_pix_format *pix = &f->fmt.pix;
struct ov772x_priv *priv;
@@ -814,9 +832,6 @@ static int ov772x_video_probe(struct soc_camera_device *icd)
icd->formats = ov772x_fmt_lists;
icd->num_formats = ARRAY_SIZE(ov772x_fmt_lists);
- if (priv->info->link.power)
- priv->info->link.power(&priv->client->dev, 1);
-
/*
* check and show product ID and manufacturer ID
*/
@@ -824,8 +839,8 @@ static int ov772x_video_probe(struct soc_camera_device *icd)
ver = i2c_smbus_read_byte_data(priv->client, VER);
if (pid != 0x77 ||
ver != 0x21) {
- if (priv->info->link.power)
- priv->info->link.power(&priv->client->dev, 0);
+ dev_err(&icd->dev,
+ "Product ID error %x:%x\n", pid, ver);
return -ENODEV;
}
@@ -842,13 +857,7 @@ static int ov772x_video_probe(struct soc_camera_device *icd)
static void ov772x_video_remove(struct soc_camera_device *icd)
{
- struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
-
soc_camera_video_stop(icd);
-
- if (priv->info->link.power)
- priv->info->link.power(&priv->client->dev, 0);
-
}
static struct soc_camera_ops ov772x_ops = {
@@ -859,8 +868,8 @@ static struct soc_camera_ops ov772x_ops = {
.release = ov772x_release,
.start_capture = ov772x_start_capture,
.stop_capture = ov772x_stop_capture,
- .set_fmt_cap = ov772x_set_fmt_cap,
- .try_fmt_cap = ov772x_try_fmt_cap,
+ .set_fmt = ov772x_set_fmt,
+ .try_fmt = ov772x_try_fmt,
.set_bus_param = ov772x_set_bus_param,
.query_bus_param = ov772x_query_bus_param,
.get_chip_id = ov772x_get_chip_id,
diff --git a/linux/drivers/media/video/pxa_camera.c b/linux/drivers/media/video/pxa_camera.c
index 08723ed84..210a99780 100644
--- a/linux/drivers/media/video/pxa_camera.c
+++ b/linux/drivers/media/video/pxa_camera.c
@@ -770,6 +770,9 @@ static int test_platform_param(struct pxa_camera_dev *pcdev,
if (!(pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_8))
return -EINVAL;
*flags |= SOCAM_DATAWIDTH_8;
+ break;
+ default:
+ return -EINVAL;
}
return 0;
@@ -828,12 +831,10 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
* We fix bit-per-pixel equal to data-width... */
switch (common_flags & SOCAM_DATAWIDTH_MASK) {
case SOCAM_DATAWIDTH_10:
- icd->buswidth = 10;
dw = 4;
bpp = 0x40;
break;
case SOCAM_DATAWIDTH_9:
- icd->buswidth = 9;
dw = 3;
bpp = 0x20;
break;
@@ -841,7 +842,6 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
/* Actually it can only be 8 now,
* default is just to silence compiler warnings */
case SOCAM_DATAWIDTH_8:
- icd->buswidth = 8;
dw = 2;
bpp = 0;
}
@@ -867,7 +867,17 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
case V4L2_PIX_FMT_YUV422P:
pcdev->channels = 3;
cicr1 |= CICR1_YCBCR_F;
+ /*
+ * Normally, pxa bus wants as input UYVY format. We allow all
+ * reorderings of the YUV422 format, as no processing is done,
+ * and the YUV stream is just passed through without any
+ * transformation. Note that UYVY is the only format that
+ * should be used if pxa framebuffer Overlay2 is used.
+ */
+ case V4L2_PIX_FMT_UYVY:
+ case V4L2_PIX_FMT_VYUY:
case V4L2_PIX_FMT_YUYV:
+ case V4L2_PIX_FMT_YVYU:
cicr1 |= CICR1_COLOR_SP_VAL(2);
break;
case V4L2_PIX_FMT_RGB555:
@@ -893,13 +903,14 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
return 0;
}
-static int pxa_camera_try_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
+static int pxa_camera_try_bus_param(struct soc_camera_device *icd,
+ unsigned char buswidth)
{
struct soc_camera_host *ici =
to_soc_camera_host(icd->dev.parent);
struct pxa_camera_dev *pcdev = ici->priv;
unsigned long bus_flags, camera_flags;
- int ret = test_platform_param(pcdev, icd->buswidth, &bus_flags);
+ int ret = test_platform_param(pcdev, buswidth, &bus_flags);
if (ret < 0)
return ret;
@@ -909,28 +920,174 @@ static int pxa_camera_try_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
return soc_camera_bus_param_compatible(camera_flags, bus_flags) ? 0 : -EINVAL;
}
-static int pxa_camera_set_fmt_cap(struct soc_camera_device *icd,
- __u32 pixfmt, struct v4l2_rect *rect)
+static const struct soc_camera_data_format pxa_camera_formats[] = {
+ {
+ .name = "Planar YUV422 16 bit",
+ .depth = 16,
+ .fourcc = V4L2_PIX_FMT_YUV422P,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ },
+};
+
+static bool buswidth_supported(struct soc_camera_device *icd, int depth)
+{
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ struct pxa_camera_dev *pcdev = ici->priv;
+
+ switch (depth) {
+ case 8:
+ return !!(pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_8);
+ case 9:
+ return !!(pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_9);
+ case 10:
+ return !!(pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_10);
+ }
+ return false;
+}
+
+static int required_buswidth(const struct soc_camera_data_format *fmt)
+{
+ switch (fmt->fourcc) {
+ case V4L2_PIX_FMT_UYVY:
+ case V4L2_PIX_FMT_VYUY:
+ case V4L2_PIX_FMT_YUYV:
+ case V4L2_PIX_FMT_YVYU:
+ case V4L2_PIX_FMT_RGB565:
+ case V4L2_PIX_FMT_RGB555:
+ return 8;
+ default:
+ return fmt->depth;
+ }
+}
+
+static int pxa_camera_get_formats(struct soc_camera_device *icd, int idx,
+ struct soc_camera_format_xlate *xlate)
+{
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ int formats = 0, buswidth, ret;
+
+ buswidth = required_buswidth(icd->formats + idx);
+
+ if (!buswidth_supported(icd, buswidth))
+ return 0;
+
+ ret = pxa_camera_try_bus_param(icd, buswidth);
+ if (ret < 0)
+ return 0;
+
+ switch (icd->formats[idx].fourcc) {
+ case V4L2_PIX_FMT_UYVY:
+ formats++;
+ if (xlate) {
+ xlate->host_fmt = &pxa_camera_formats[0];
+ xlate->cam_fmt = icd->formats + idx;
+ xlate->buswidth = buswidth;
+ xlate++;
+ dev_dbg(&ici->dev, "Providing format %s using %s\n",
+ pxa_camera_formats[0].name,
+ icd->formats[idx].name);
+ }
+ case V4L2_PIX_FMT_VYUY:
+ case V4L2_PIX_FMT_YUYV:
+ case V4L2_PIX_FMT_YVYU:
+ case V4L2_PIX_FMT_RGB565:
+ case V4L2_PIX_FMT_RGB555:
+ formats++;
+ if (xlate) {
+ xlate->host_fmt = icd->formats + idx;
+ xlate->cam_fmt = icd->formats + idx;
+ xlate->buswidth = buswidth;
+ xlate++;
+ dev_dbg(&ici->dev, "Providing format %s packed\n",
+ icd->formats[idx].name);
+ }
+ break;
+ default:
+ /* Generic pass-through */
+ formats++;
+ if (xlate) {
+ xlate->host_fmt = icd->formats + idx;
+ xlate->cam_fmt = icd->formats + idx;
+ xlate->buswidth = icd->formats[idx].depth;
+ xlate++;
+ dev_dbg(&ici->dev,
+ "Providing format %s in pass-through mode\n",
+ icd->formats[idx].name);
+ }
+ }
+
+ return formats;
+}
+
+static int pxa_camera_set_fmt(struct soc_camera_device *icd,
+ __u32 pixfmt, struct v4l2_rect *rect)
{
- return icd->ops->set_fmt_cap(icd, pixfmt, rect);
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ const struct soc_camera_data_format *host_fmt, *cam_fmt = NULL;
+ const struct soc_camera_format_xlate *xlate;
+ int ret, buswidth;
+
+ xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
+ if (!xlate) {
+ dev_warn(&ici->dev, "Format %x not found\n", pixfmt);
+ return -EINVAL;
+ }
+
+ buswidth = xlate->buswidth;
+ host_fmt = xlate->host_fmt;
+ cam_fmt = xlate->cam_fmt;
+
+ switch (pixfmt) {
+ case 0: /* Only geometry change */
+ ret = icd->ops->set_fmt(icd, pixfmt, rect);
+ break;
+ default:
+ ret = icd->ops->set_fmt(icd, cam_fmt->fourcc, rect);
+ }
+
+ if (ret < 0)
+ dev_warn(&ici->dev, "Failed to configure for format %x\n",
+ pixfmt);
+
+ if (pixfmt && !ret) {
+ icd->buswidth = buswidth;
+ icd->current_fmt = host_fmt;
+ }
+
+ return ret;
}
-static int pxa_camera_try_fmt_cap(struct soc_camera_device *icd,
- struct v4l2_format *f)
+static int pxa_camera_try_fmt(struct soc_camera_device *icd,
+ struct v4l2_format *f)
{
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ const struct soc_camera_format_xlate *xlate;
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+ __u32 pixfmt = pix->pixelformat;
+
+ xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
+ if (!xlate) {
+ dev_warn(&ici->dev, "Format %x not found\n", pixfmt);
+ return -EINVAL;
+ }
+
/* limit to pxa hardware capabilities */
- if (f->fmt.pix.height < 32)
- f->fmt.pix.height = 32;
- if (f->fmt.pix.height > 2048)
- f->fmt.pix.height = 2048;
- if (f->fmt.pix.width < 48)
- f->fmt.pix.width = 48;
- if (f->fmt.pix.width > 2048)
- f->fmt.pix.width = 2048;
- f->fmt.pix.width &= ~0x01;
+ if (pix->height < 32)
+ pix->height = 32;
+ if (pix->height > 2048)
+ pix->height = 2048;
+ if (pix->width < 48)
+ pix->width = 48;
+ if (pix->width > 2048)
+ pix->width = 2048;
+ pix->width &= ~0x01;
+
+ pix->bytesperline = pix->width *
+ DIV_ROUND_UP(xlate->host_fmt->depth, 8);
+ pix->sizeimage = pix->height * pix->bytesperline;
/* limit to sensor capabilities */
- return icd->ops->try_fmt_cap(icd, f);
+ return icd->ops->try_fmt(icd, f);
}
static int pxa_camera_reqbufs(struct soc_camera_file *icf,
@@ -1038,13 +1195,13 @@ static struct soc_camera_host_ops pxa_soc_camera_host_ops = {
.remove = pxa_camera_remove_device,
.suspend = pxa_camera_suspend,
.resume = pxa_camera_resume,
- .set_fmt_cap = pxa_camera_set_fmt_cap,
- .try_fmt_cap = pxa_camera_try_fmt_cap,
+ .get_formats = pxa_camera_get_formats,
+ .set_fmt = pxa_camera_set_fmt,
+ .try_fmt = pxa_camera_try_fmt,
.init_videobuf = pxa_camera_init_videobuf,
.reqbufs = pxa_camera_reqbufs,
.poll = pxa_camera_poll,
.querycap = pxa_camera_querycap,
- .try_bus_param = pxa_camera_try_bus_param,
.set_bus_param = pxa_camera_set_bus_param,
};
diff --git a/linux/drivers/media/video/sh_mobile_ceu_camera.c b/linux/drivers/media/video/sh_mobile_ceu_camera.c
index 2fb8bee0b..e2e816213 100644
--- a/linux/drivers/media/video/sh_mobile_ceu_camera.c
+++ b/linux/drivers/media/video/sh_mobile_ceu_camera.c
@@ -445,15 +445,46 @@ static int sh_mobile_ceu_try_bus_param(struct soc_camera_device *icd,
return 0;
}
-static int sh_mobile_ceu_set_fmt_cap(struct soc_camera_device *icd,
- __u32 pixfmt, struct v4l2_rect *rect)
+static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd,
+ __u32 pixfmt, struct v4l2_rect *rect)
{
- return icd->ops->set_fmt_cap(icd, pixfmt, rect);
+ const struct soc_camera_data_format *cam_fmt;
+ int ret;
+
+ /*
+ * TODO: find a suitable supported by the SoC output format, check
+ * whether the sensor supports one of acceptable input formats.
+ */
+ if (pixfmt) {
+ cam_fmt = soc_camera_format_by_fourcc(icd, pixfmt);
+ if (!cam_fmt)
+ return -EINVAL;
+ }
+
+ ret = icd->ops->set_fmt(icd, pixfmt, rect);
+ if (pixfmt && !ret)
+ icd->current_fmt = cam_fmt;
+
+ return ret;
}
-static int sh_mobile_ceu_try_fmt_cap(struct soc_camera_device *icd,
- struct v4l2_format *f)
+static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd,
+ struct v4l2_format *f)
{
+ const struct soc_camera_data_format *cam_fmt;
+ int ret = sh_mobile_ceu_try_bus_param(icd, f->fmt.pix.pixelformat);
+
+ if (ret < 0)
+ return ret;
+
+ /*
+ * TODO: find a suitable supported by the SoC output format, check
+ * whether the sensor supports one of acceptable input formats.
+ */
+ cam_fmt = soc_camera_format_by_fourcc(icd, f->fmt.pix.pixelformat);
+ if (!cam_fmt)
+ return -EINVAL;
+
/* FIXME: calculate using depth and bus width */
if (f->fmt.pix.height < 4)
@@ -467,8 +498,12 @@ static int sh_mobile_ceu_try_fmt_cap(struct soc_camera_device *icd,
f->fmt.pix.width &= ~0x01;
f->fmt.pix.height &= ~0x03;
+ f->fmt.pix.bytesperline = f->fmt.pix.width *
+ DIV_ROUND_UP(cam_fmt->depth, 8);
+ f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
+
/* limit to sensor capabilities */
- return icd->ops->try_fmt_cap(icd, f);
+ return icd->ops->try_fmt(icd, f);
}
static int sh_mobile_ceu_reqbufs(struct soc_camera_file *icf,
@@ -536,12 +571,11 @@ static struct soc_camera_host_ops sh_mobile_ceu_host_ops = {
.owner = THIS_MODULE,
.add = sh_mobile_ceu_add_device,
.remove = sh_mobile_ceu_remove_device,
- .set_fmt_cap = sh_mobile_ceu_set_fmt_cap,
- .try_fmt_cap = sh_mobile_ceu_try_fmt_cap,
+ .set_fmt = sh_mobile_ceu_set_fmt,
+ .try_fmt = sh_mobile_ceu_try_fmt,
.reqbufs = sh_mobile_ceu_reqbufs,
.poll = sh_mobile_ceu_poll,
.querycap = sh_mobile_ceu_querycap,
- .try_bus_param = sh_mobile_ceu_try_bus_param,
.set_bus_param = sh_mobile_ceu_set_bus_param,
.init_videobuf = sh_mobile_ceu_init_videobuf,
};
diff --git a/linux/drivers/media/video/soc_camera.c b/linux/drivers/media/video/soc_camera.c
index 7a46697c4..4a9c52c37 100644
--- a/linux/drivers/media/video/soc_camera.c
+++ b/linux/drivers/media/video/soc_camera.c
@@ -36,8 +36,8 @@ static LIST_HEAD(devices);
static DEFINE_MUTEX(list_lock);
static DEFINE_MUTEX(video_lock);
-const static struct soc_camera_data_format*
-format_by_fourcc(struct soc_camera_device *icd, unsigned int fourcc)
+const struct soc_camera_data_format *soc_camera_format_by_fourcc(
+ struct soc_camera_device *icd, unsigned int fourcc)
{
unsigned int i;
@@ -46,52 +46,47 @@ format_by_fourcc(struct soc_camera_device *icd, unsigned int fourcc)
return icd->formats + i;
return NULL;
}
+EXPORT_SYMBOL(soc_camera_format_by_fourcc);
+
+const struct soc_camera_format_xlate *soc_camera_xlate_by_fourcc(
+ struct soc_camera_device *icd, unsigned int fourcc)
+{
+ unsigned int i;
+
+ for (i = 0; i < icd->num_user_formats; i++)
+ if (icd->user_formats[i].host_fmt->fourcc == fourcc)
+ return icd->user_formats + i;
+ return NULL;
+}
+EXPORT_SYMBOL(soc_camera_xlate_by_fourcc);
static int soc_camera_try_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *f)
+ struct v4l2_format *f)
{
struct soc_camera_file *icf = file->private_data;
struct soc_camera_device *icd = icf->icd;
struct soc_camera_host *ici =
to_soc_camera_host(icd->dev.parent);
enum v4l2_field field;
- const struct soc_camera_data_format *fmt;
int ret;
WARN_ON(priv != file->private_data);
- fmt = format_by_fourcc(icd, f->fmt.pix.pixelformat);
- if (!fmt) {
- dev_dbg(&icd->dev, "invalid format 0x%08x\n",
- f->fmt.pix.pixelformat);
- return -EINVAL;
- }
-
- dev_dbg(&icd->dev, "fmt: 0x%08x\n", fmt->fourcc);
-
+ /*
+ * TODO: this might also have to migrate to host-drivers, if anyone
+ * wishes to support other fields
+ */
field = f->fmt.pix.field;
if (field == V4L2_FIELD_ANY) {
- field = V4L2_FIELD_NONE;
- } else if (V4L2_FIELD_NONE != field) {
+ f->fmt.pix.field = V4L2_FIELD_NONE;
+ } else if (field != V4L2_FIELD_NONE) {
dev_err(&icd->dev, "Field type invalid.\n");
return -EINVAL;
}
- /* test physical bus parameters */
- ret = ici->ops->try_bus_param(icd, f->fmt.pix.pixelformat);
- if (ret)
- return ret;
-
/* limit format to hardware capabilities */
- ret = ici->ops->try_fmt_cap(icd, f);
-
- /* calculate missing fields */
- f->fmt.pix.field = field;
- f->fmt.pix.bytesperline =
- (f->fmt.pix.width * fmt->depth) >> 3;
- f->fmt.pix.sizeimage =
- f->fmt.pix.height * f->fmt.pix.bytesperline;
+ ret = ici->ops->try_fmt(icd, f);
return ret;
}
@@ -179,6 +174,59 @@ static int soc_camera_dqbuf(struct file *file, void *priv,
return videobuf_dqbuf(&icf->vb_vidq, p, file->f_flags & O_NONBLOCK);
}
+static int soc_camera_init_user_formats(struct soc_camera_device *icd)
+{
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ int i, fmts = 0;
+
+ if (!ici->ops->get_formats)
+ /*
+ * Fallback mode - the host will have to serve all
+ * sensor-provided formats one-to-one to the user
+ */
+ fmts = icd->num_formats;
+ else
+ /*
+ * First pass - only count formats this host-sensor
+ * configuration can provide
+ */
+ for (i = 0; i < icd->num_formats; i++)
+ fmts += ici->ops->get_formats(icd, i, NULL);
+
+ if (!fmts)
+ return -ENXIO;
+
+ icd->user_formats =
+ vmalloc(fmts * sizeof(struct soc_camera_format_xlate));
+ if (!icd->user_formats)
+ return -ENOMEM;
+
+ icd->num_user_formats = fmts;
+ fmts = 0;
+
+ dev_dbg(&icd->dev, "Found %d supported formats.\n", fmts);
+
+ /* Second pass - actually fill data formats */
+ for (i = 0; i < icd->num_formats; i++)
+ if (!ici->ops->get_formats) {
+ icd->user_formats[i].host_fmt = icd->formats + i;
+ icd->user_formats[i].cam_fmt = icd->formats + i;
+ icd->user_formats[i].buswidth = icd->formats[i].depth;
+ } else {
+ fmts += ici->ops->get_formats(icd, i,
+ &icd->user_formats[fmts]);
+ }
+
+ icd->current_fmt = icd->user_formats[0].host_fmt;
+
+ return 0;
+}
+
+static void soc_camera_free_user_formats(struct soc_camera_device *icd)
+{
+ vfree(icd->user_formats);
+}
+
static int soc_camera_open(struct inode *inode, struct file *file)
{
struct video_device *vdev;
@@ -215,10 +263,12 @@ static int soc_camera_open(struct inode *inode, struct file *file)
/* Now we really have to activate the camera */
if (icd->use_count == 1) {
+ ret = soc_camera_init_user_formats(icd);
+ if (ret < 0)
+ goto eiufmt;
ret = ici->ops->add(icd);
if (ret < 0) {
dev_err(&icd->dev, "Couldn't activate the camera: %d\n", ret);
- icd->use_count--;
goto eiciadd;
}
}
@@ -234,6 +284,9 @@ static int soc_camera_open(struct inode *inode, struct file *file)
/* All errors are entered with the video_lock held */
eiciadd:
+ soc_camera_free_user_formats(icd);
+eiufmt:
+ icd->use_count--;
module_put(ici->ops->owner);
emgi:
module_put(icd->ops->owner);
@@ -252,8 +305,10 @@ static int soc_camera_close(struct inode *inode, struct file *file)
mutex_lock(&video_lock);
icd->use_count--;
- if (!icd->use_count)
+ if (!icd->use_count) {
ici->ops->remove(icd);
+ soc_camera_free_user_formats(icd);
+ }
module_put(icd->ops->owner);
module_put(ici->ops->owner);
mutex_unlock(&video_lock);
@@ -266,7 +321,7 @@ static int soc_camera_close(struct inode *inode, struct file *file)
}
static ssize_t soc_camera_read(struct file *file, char __user *buf,
- size_t count, loff_t *ppos)
+ size_t count, loff_t *ppos)
{
struct soc_camera_file *icf = file->private_data;
struct soc_camera_device *icd = icf->icd;
@@ -311,7 +366,6 @@ static unsigned int soc_camera_poll(struct file *file, poll_table *pt)
return ici->ops->poll(file, pt);
}
-
static struct file_operations soc_camera_fops = {
.owner = THIS_MODULE,
.open = soc_camera_open,
@@ -323,28 +377,20 @@ static struct file_operations soc_camera_fops = {
.llseek = no_llseek,
};
-
static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *f)
+ struct v4l2_format *f)
{
struct soc_camera_file *icf = file->private_data;
struct soc_camera_device *icd = icf->icd;
struct soc_camera_host *ici =
to_soc_camera_host(icd->dev.parent);
+ __u32 pixfmt = f->fmt.pix.pixelformat;
int ret;
struct v4l2_rect rect;
- const static struct soc_camera_data_format *data_fmt;
WARN_ON(priv != file->private_data);
- data_fmt = format_by_fourcc(icd, f->fmt.pix.pixelformat);
- if (!data_fmt)
- return -EINVAL;
-
- /* buswidth may be further adjusted by the ici */
- icd->buswidth = data_fmt->depth;
-
- ret = soc_camera_try_fmt_vid_cap(file, icf, f);
+ ret = soc_camera_try_fmt_vid_cap(file, priv, f);
if (ret < 0)
return ret;
@@ -352,15 +398,20 @@ static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv,
rect.top = icd->y_current;
rect.width = f->fmt.pix.width;
rect.height = f->fmt.pix.height;
- ret = ici->ops->set_fmt_cap(icd, f->fmt.pix.pixelformat, &rect);
- if (ret < 0)
+ ret = ici->ops->set_fmt(icd, f->fmt.pix.pixelformat, &rect);
+ if (ret < 0) {
return ret;
+ } else if (!icd->current_fmt ||
+ icd->current_fmt->fourcc != pixfmt) {
+ dev_err(&ici->dev,
+ "Host driver hasn't set up current format correctly!\n");
+ return -EINVAL;
+ }
- icd->current_fmt = data_fmt;
icd->width = rect.width;
icd->height = rect.height;
icf->vb_vidq.field = f->fmt.pix.field;
- if (V4L2_BUF_TYPE_VIDEO_CAPTURE != f->type)
+ if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
dev_warn(&icd->dev, "Attention! Wrong buf-type %d\n",
f->type);
@@ -368,11 +419,11 @@ static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv,
icd->width, icd->height);
/* set physical bus parameters */
- return ici->ops->set_bus_param(icd, f->fmt.pix.pixelformat);
+ return ici->ops->set_bus_param(icd, pixfmt);
}
static int soc_camera_enum_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_fmtdesc *f)
+ struct v4l2_fmtdesc *f)
{
struct soc_camera_file *icf = file->private_data;
struct soc_camera_device *icd = icf->icd;
@@ -380,10 +431,10 @@ static int soc_camera_enum_fmt_vid_cap(struct file *file, void *priv,
WARN_ON(priv != file->private_data);
- if (f->index >= icd->num_formats)
+ if (f->index >= icd->num_user_formats)
return -EINVAL;
- format = &icd->formats[f->index];
+ format = icd->user_formats[f->index].host_fmt;
strlcpy(f->description, format->name, sizeof(f->description));
f->pixelformat = format->fourcc;
@@ -391,7 +442,7 @@ static int soc_camera_enum_fmt_vid_cap(struct file *file, void *priv,
}
static int soc_camera_g_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *f)
+ struct v4l2_format *f)
{
struct soc_camera_file *icf = file->private_data;
struct soc_camera_device *icd = icf->icd;
@@ -402,10 +453,9 @@ static int soc_camera_g_fmt_vid_cap(struct file *file, void *priv,
f->fmt.pix.height = icd->height;
f->fmt.pix.field = icf->vb_vidq.field;
f->fmt.pix.pixelformat = icd->current_fmt->fourcc;
- f->fmt.pix.bytesperline =
- (f->fmt.pix.width * icd->current_fmt->depth) >> 3;
- f->fmt.pix.sizeimage =
- f->fmt.pix.height * f->fmt.pix.bytesperline;
+ f->fmt.pix.bytesperline = f->fmt.pix.width *
+ DIV_ROUND_UP(icd->current_fmt->depth, 8);
+ f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
dev_dbg(&icd->dev, "current_fmt->fourcc: 0x%08x\n",
icd->current_fmt->fourcc);
return 0;
@@ -575,7 +625,7 @@ static int soc_camera_s_crop(struct file *file, void *fh,
if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
- ret = ici->ops->set_fmt_cap(icd, 0, &a->c);
+ ret = ici->ops->set_fmt(icd, 0, &a->c);
if (!ret) {
icd->width = a->c.width;
icd->height = a->c.height;
@@ -941,8 +991,6 @@ int soc_camera_video_start(struct soc_camera_device *icd)
vdev->minor = -1;
vdev->tvnorms = V4L2_STD_UNKNOWN,
- icd->current_fmt = &icd->formats[0];
-
err = video_register_device(vdev, VFL_TYPE_GRABBER, vdev->minor);
if (err < 0) {
dev_err(vdev->parent, "video_register_device failed\n");
diff --git a/linux/drivers/media/video/soc_camera_platform.c b/linux/drivers/media/video/soc_camera_platform.c
index bb7a9d480..c23871e4c 100644
--- a/linux/drivers/media/video/soc_camera_platform.c
+++ b/linux/drivers/media/video/soc_camera_platform.c
@@ -79,14 +79,14 @@ soc_camera_platform_query_bus_param(struct soc_camera_device *icd)
return p->bus_param;
}
-static int soc_camera_platform_set_fmt_cap(struct soc_camera_device *icd,
- __u32 pixfmt, struct v4l2_rect *rect)
+static int soc_camera_platform_set_fmt(struct soc_camera_device *icd,
+ __u32 pixfmt, struct v4l2_rect *rect)
{
return 0;
}
-static int soc_camera_platform_try_fmt_cap(struct soc_camera_device *icd,
- struct v4l2_format *f)
+static int soc_camera_platform_try_fmt(struct soc_camera_device *icd,
+ struct v4l2_format *f)
{
struct soc_camera_platform_info *p = soc_camera_platform_get_info(icd);
@@ -124,8 +124,8 @@ static struct soc_camera_ops soc_camera_platform_ops = {
.release = soc_camera_platform_release,
.start_capture = soc_camera_platform_start_capture,
.stop_capture = soc_camera_platform_stop_capture,
- .set_fmt_cap = soc_camera_platform_set_fmt_cap,
- .try_fmt_cap = soc_camera_platform_try_fmt_cap,
+ .set_fmt = soc_camera_platform_set_fmt,
+ .try_fmt = soc_camera_platform_try_fmt,
.set_bus_param = soc_camera_platform_set_bus_param,
.query_bus_param = soc_camera_platform_query_bus_param,
};
diff --git a/linux/include/media/soc_camera.h b/linux/include/media/soc_camera.h
index 9231e2d90..da57ffdae 100644
--- a/linux/include/media/soc_camera.h
+++ b/linux/include/media/soc_camera.h
@@ -41,7 +41,10 @@ struct soc_camera_device {
const struct soc_camera_data_format *current_fmt;
const struct soc_camera_data_format *formats;
int num_formats;
+ struct soc_camera_format_xlate *user_formats;
+ int num_user_formats;
struct module *owner;
+ void *host_priv; /* per-device host private data */
/* soc_camera.c private count. Only accessed with video_lock held */
int use_count;
};
@@ -64,16 +67,16 @@ struct soc_camera_host_ops {
struct module *owner;
int (*add)(struct soc_camera_device *);
void (*remove)(struct soc_camera_device *);
- int (*suspend)(struct soc_camera_device *, pm_message_t state);
+ int (*suspend)(struct soc_camera_device *, pm_message_t);
int (*resume)(struct soc_camera_device *);
- int (*set_fmt_cap)(struct soc_camera_device *, __u32,
- struct v4l2_rect *);
- int (*try_fmt_cap)(struct soc_camera_device *, struct v4l2_format *);
+ int (*get_formats)(struct soc_camera_device *, int,
+ struct soc_camera_format_xlate *);
+ int (*set_fmt)(struct soc_camera_device *, __u32, struct v4l2_rect *);
+ int (*try_fmt)(struct soc_camera_device *, struct v4l2_format *);
void (*init_videobuf)(struct videobuf_queue *,
struct soc_camera_device *);
int (*reqbufs)(struct soc_camera_file *, struct v4l2_requestbuffers *);
int (*querycap)(struct soc_camera_host *, struct v4l2_capability *);
- int (*try_bus_param)(struct soc_camera_device *, __u32);
int (*set_bus_param)(struct soc_camera_device *, __u32);
unsigned int (*poll)(struct file *, poll_table *);
};
@@ -106,6 +109,11 @@ extern void soc_camera_device_unregister(struct soc_camera_device *icd);
extern int soc_camera_video_start(struct soc_camera_device *icd);
extern void soc_camera_video_stop(struct soc_camera_device *icd);
+extern const struct soc_camera_data_format *soc_camera_format_by_fourcc(
+ struct soc_camera_device *icd, unsigned int fourcc);
+extern const struct soc_camera_format_xlate *soc_camera_xlate_by_fourcc(
+ struct soc_camera_device *icd, unsigned int fourcc);
+
struct soc_camera_data_format {
const char *name;
unsigned int depth;
@@ -113,6 +121,23 @@ struct soc_camera_data_format {
enum v4l2_colorspace colorspace;
};
+/**
+ * struct soc_camera_format_xlate - match between host and sensor formats
+ * @cam_fmt: sensor format provided by the sensor
+ * @host_fmt: host format after host translation from cam_fmt
+ * @buswidth: bus width for this format
+ *
+ * Host and sensor translation structure. Used in table of host and sensor
+ * formats matchings in soc_camera_device. A host can override the generic list
+ * generation by implementing get_formats(), and use it for format checks and
+ * format setup.
+ */
+struct soc_camera_format_xlate {
+ const struct soc_camera_data_format *cam_fmt;
+ const struct soc_camera_data_format *host_fmt;
+ unsigned char buswidth;
+};
+
struct soc_camera_ops {
struct module *owner;
int (*probe)(struct soc_camera_device *);
@@ -123,9 +148,8 @@ struct soc_camera_ops {
int (*release)(struct soc_camera_device *);
int (*start_capture)(struct soc_camera_device *);
int (*stop_capture)(struct soc_camera_device *);
- int (*set_fmt_cap)(struct soc_camera_device *, __u32,
- struct v4l2_rect *);
- int (*try_fmt_cap)(struct soc_camera_device *, struct v4l2_format *);
+ int (*set_fmt)(struct soc_camera_device *, __u32, struct v4l2_rect *);
+ int (*try_fmt)(struct soc_camera_device *, struct v4l2_format *);
unsigned long (*query_bus_param)(struct soc_camera_device *);
int (*set_bus_param)(struct soc_camera_device *, unsigned long);
int (*get_chip_id)(struct soc_camera_device *,