summaryrefslogtreecommitdiffstats
path: root/drivers/media/video/pxa_camera.c
diff options
context:
space:
mode:
authorGuennadi Liakhovetski <g.liakhovetski@pengutronix.de>2008-03-07 21:57:18 -0300
committerMauro Carvalho Chehab <mchehab@infradead.org>2008-04-24 14:07:49 -0300
commitad5f2e859d76dccb7eb1aa942171b1a32211efc2 (patch)
tree1716d5c82322d55886de36dddd9535b90dd57630 /drivers/media/video/pxa_camera.c
parent1c659689fe9959c017bfaaa8301243f7d99f1a46 (diff)
V4L/DVB (7336): soc-camera: streamline hardware parameter negotiation
Improve hardware parameter negotiation between the camera host driver and camera drivers. Parameters like horizontal and vertical synchronisation, pixel clock polarity shall be set depending on capabilities of the parties. Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@pengutronix.de> Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'drivers/media/video/pxa_camera.c')
-rw-r--r--drivers/media/video/pxa_camera.c156
1 files changed, 113 insertions, 43 deletions
diff --git a/drivers/media/video/pxa_camera.c b/drivers/media/video/pxa_camera.c
index a34a193249f..4756699d16a 100644
--- a/drivers/media/video/pxa_camera.c
+++ b/drivers/media/video/pxa_camera.c
@@ -581,64 +581,109 @@ static void pxa_camera_remove_device(struct soc_camera_device *icd)
pcdev->icd = NULL;
}
-static int pxa_camera_set_capture_format(struct soc_camera_device *icd,
- __u32 pixfmt, struct v4l2_rect *rect)
+static int test_platform_param(struct pxa_camera_dev *pcdev,
+ unsigned char buswidth, unsigned long *flags)
{
- struct soc_camera_host *ici =
- to_soc_camera_host(icd->dev.parent);
- struct pxa_camera_dev *pcdev = ici->priv;
- unsigned int datawidth = 0, dw, bpp;
- u32 cicr0, cicr4 = 0;
- int ret;
+ /*
+ * Platform specified synchronization and pixel clock polarities are
+ * only a recommendation and are only used during probing. The PXA270
+ * quick capture interface supports both.
+ */
+ *flags = (pcdev->platform_flags & PXA_CAMERA_MASTER ?
+ SOCAM_MASTER : SOCAM_SLAVE) |
+ SOCAM_HSYNC_ACTIVE_HIGH |
+ SOCAM_HSYNC_ACTIVE_LOW |
+ SOCAM_VSYNC_ACTIVE_HIGH |
+ SOCAM_VSYNC_ACTIVE_LOW |
+ SOCAM_PCLK_SAMPLE_RISING |
+ SOCAM_PCLK_SAMPLE_FALLING;
/* If requested data width is supported by the platform, use it */
- switch (icd->cached_datawidth) {
+ switch (buswidth) {
case 10:
- if (pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_10)
- datawidth = IS_DATAWIDTH_10;
+ if (!(pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_10))
+ return -EINVAL;
+ *flags |= SOCAM_DATAWIDTH_10;
break;
case 9:
- if (pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_9)
- datawidth = IS_DATAWIDTH_9;
+ if (!(pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_9))
+ return -EINVAL;
+ *flags |= SOCAM_DATAWIDTH_9;
break;
case 8:
- if (pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_8)
- datawidth = IS_DATAWIDTH_8;
+ if (!(pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_8))
+ return -EINVAL;
+ *flags |= SOCAM_DATAWIDTH_8;
}
- if (!datawidth)
+
+ return 0;
+}
+
+static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
+{
+ struct soc_camera_host *ici =
+ to_soc_camera_host(icd->dev.parent);
+ struct pxa_camera_dev *pcdev = ici->priv;
+ unsigned long dw, bpp, bus_flags, camera_flags, common_flags;
+ u32 cicr0, cicr4 = 0;
+ int ret = test_platform_param(pcdev, icd->buswidth, &bus_flags);
+
+ if (ret < 0)
+ return ret;
+
+ camera_flags = icd->ops->query_bus_param(icd);
+
+ common_flags = soc_camera_bus_param_compatible(camera_flags, bus_flags);
+ if (!common_flags)
return -EINVAL;
- ret = icd->ops->set_capture_format(icd, pixfmt, rect,
- datawidth |
- (pcdev->platform_flags & PXA_CAMERA_MASTER ?
- IS_MASTER : 0) |
- (pcdev->platform_flags & PXA_CAMERA_HSP ?
- 0 : IS_HSYNC_ACTIVE_HIGH) |
- (pcdev->platform_flags & PXA_CAMERA_VSP ?
- 0 : IS_VSYNC_ACTIVE_HIGH) |
- (pcdev->platform_flags & PXA_CAMERA_PCP ?
- 0 : IS_PCLK_SAMPLE_RISING));
+ /* Make choises, based on platform preferences */
+ if ((common_flags & SOCAM_HSYNC_ACTIVE_HIGH) &&
+ (common_flags & SOCAM_HSYNC_ACTIVE_LOW)) {
+ if (pcdev->platform_flags & PXA_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 (pcdev->platform_flags & PXA_CAMERA_VSP)
+ common_flags &= ~SOCAM_VSYNC_ACTIVE_HIGH;
+ else
+ common_flags &= ~SOCAM_VSYNC_ACTIVE_LOW;
+ }
+
+ if ((common_flags & SOCAM_PCLK_SAMPLE_RISING) &&
+ (common_flags & SOCAM_PCLK_SAMPLE_FALLING)) {
+ if (pcdev->platform_flags & PXA_CAMERA_PCP)
+ common_flags &= ~SOCAM_PCLK_SAMPLE_RISING;
+ else
+ common_flags &= ~SOCAM_PCLK_SAMPLE_FALLING;
+ }
+
+ ret = icd->ops->set_bus_param(icd, common_flags);
if (ret < 0)
return ret;
/* Datawidth is now guaranteed to be equal to one of the three values.
* We fix bit-per-pixel equal to data-width... */
- switch (datawidth) {
- case IS_DATAWIDTH_10:
- icd->cached_datawidth = 10;
+ switch (common_flags & SOCAM_DATAWIDTH_MASK) {
+ case SOCAM_DATAWIDTH_10:
+ icd->buswidth = 10;
dw = 4;
bpp = 0x40;
break;
- case IS_DATAWIDTH_9:
- icd->cached_datawidth = 9;
+ case SOCAM_DATAWIDTH_9:
+ icd->buswidth = 9;
dw = 3;
bpp = 0x20;
break;
default:
/* Actually it can only be 8 now,
* default is just to silence compiler warnings */
- case IS_DATAWIDTH_8:
- icd->cached_datawidth = 8;
+ case SOCAM_DATAWIDTH_8:
+ icd->buswidth = 8;
dw = 2;
bpp = 0;
}
@@ -647,19 +692,19 @@ static int pxa_camera_set_capture_format(struct soc_camera_device *icd,
cicr4 |= CICR4_PCLK_EN;
if (pcdev->platform_flags & PXA_CAMERA_MCLK_EN)
cicr4 |= CICR4_MCLK_EN;
- if (pcdev->platform_flags & PXA_CAMERA_PCP)
+ if (common_flags & SOCAM_PCLK_SAMPLE_FALLING)
cicr4 |= CICR4_PCP;
- if (pcdev->platform_flags & PXA_CAMERA_HSP)
+ if (common_flags & SOCAM_HSYNC_ACTIVE_LOW)
cicr4 |= CICR4_HSP;
- if (pcdev->platform_flags & PXA_CAMERA_VSP)
+ if (common_flags & SOCAM_VSYNC_ACTIVE_LOW)
cicr4 |= CICR4_VSP;
cicr0 = CICR0;
if (cicr0 & CICR0_ENB)
CICR0 = cicr0 & ~CICR0_ENB;
- CICR1 = CICR1_PPL_VAL(rect->width - 1) | bpp | dw;
+ CICR1 = CICR1_PPL_VAL(icd->width - 1) | bpp | dw;
CICR2 = 0;
- CICR3 = CICR3_LPF_VAL(rect->height - 1) |
+ CICR3 = CICR3_LPF_VAL(icd->height - 1) |
CICR3_BFW_VAL(min((unsigned short)255, icd->y_skip_top));
CICR4 = mclk_get_divisor(pcdev) | cicr4;
@@ -671,7 +716,29 @@ static int pxa_camera_set_capture_format(struct soc_camera_device *icd,
return 0;
}
-static int pxa_camera_try_fmt_cap(struct soc_camera_host *ici,
+static int pxa_camera_try_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
+{
+ 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);
+
+ if (ret < 0)
+ return ret;
+
+ camera_flags = icd->ops->query_bus_param(icd);
+
+ 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)
+{
+ return icd->ops->set_fmt_cap(icd, pixfmt, rect);
+}
+
+static int pxa_camera_try_fmt_cap(struct soc_camera_device *icd,
struct v4l2_format *f)
{
/* limit to pxa hardware capabilities */
@@ -685,7 +752,8 @@ static int pxa_camera_try_fmt_cap(struct soc_camera_host *ici,
f->fmt.pix.width = 2048;
f->fmt.pix.width &= ~0x01;
- return 0;
+ /* limit to sensor capabilities */
+ return icd->ops->try_fmt_cap(icd, f);
}
static int pxa_camera_reqbufs(struct soc_camera_file *icf,
@@ -742,11 +810,13 @@ static struct soc_camera_host pxa_soc_camera_host = {
.add = pxa_camera_add_device,
.remove = pxa_camera_remove_device,
.msize = sizeof(struct pxa_buffer),
- .set_capture_format = pxa_camera_set_capture_format,
+ .set_fmt_cap = pxa_camera_set_fmt_cap,
.try_fmt_cap = pxa_camera_try_fmt_cap,
.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,
};
static int pxa_camera_probe(struct platform_device *pdev)
@@ -782,8 +852,8 @@ static int pxa_camera_probe(struct platform_device *pdev)
pcdev->pdata = pdev->dev.platform_data;
pcdev->platform_flags = pcdev->pdata->flags;
- if (!pcdev->platform_flags & (PXA_CAMERA_DATAWIDTH_8 |
- PXA_CAMERA_DATAWIDTH_9 | PXA_CAMERA_DATAWIDTH_10)) {
+ if (!(pcdev->platform_flags & (PXA_CAMERA_DATAWIDTH_8 |
+ PXA_CAMERA_DATAWIDTH_9 | PXA_CAMERA_DATAWIDTH_10))) {
/* Platform hasn't set available data widths. This is bad.
* Warn and use a default. */
dev_warn(&pdev->dev, "WARNING! Platform hasn't set available "