Commit ad5f2e85 authored by Guennadi Liakhovetski's avatar Guennadi Liakhovetski Committed by Mauro Carvalho Chehab

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: default avatarGuennadi Liakhovetski <g.liakhovetski@pengutronix.de>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@infradead.org>
parent 1c659689
...@@ -210,40 +210,64 @@ static int bus_switch_act(struct mt9m001 *mt9m001, int go8bit) ...@@ -210,40 +210,64 @@ static int bus_switch_act(struct mt9m001 *mt9m001, int go8bit)
#endif #endif
} }
static int mt9m001_set_capture_format(struct soc_camera_device *icd, static int bus_switch_possible(struct mt9m001 *mt9m001)
__u32 pixfmt, struct v4l2_rect *rect, unsigned int flags) {
#ifdef CONFIG_MT9M001_PCA9536_SWITCH
return gpio_is_valid(mt9m001->switch_gpio);
#else
return 0;
#endif
}
static int mt9m001_set_bus_param(struct soc_camera_device *icd,
unsigned long flags)
{ {
struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd); struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
unsigned int width_flag = flags & (IS_DATAWIDTH_10 | IS_DATAWIDTH_9 | unsigned int width_flag = flags & SOCAM_DATAWIDTH_MASK;
IS_DATAWIDTH_8);
int ret; int ret;
const u16 hblank = 9, vblank = 25;
/* MT9M001 has all capture_format parameters fixed */ /* Flags validity verified in test_bus_param */
if (!(flags & IS_MASTER) ||
!(flags & IS_PCLK_SAMPLE_RISING) ||
!(flags & IS_HSYNC_ACTIVE_HIGH) ||
!(flags & IS_VSYNC_ACTIVE_HIGH))
return -EINVAL;
/* Only one width bit may be set */
if (!is_power_of_2(width_flag))
return -EINVAL;
if ((mt9m001->datawidth != 10 && (width_flag == IS_DATAWIDTH_10)) || if ((mt9m001->datawidth != 10 && (width_flag == SOCAM_DATAWIDTH_10)) ||
(mt9m001->datawidth != 9 && (width_flag == IS_DATAWIDTH_9)) || (mt9m001->datawidth != 9 && (width_flag == SOCAM_DATAWIDTH_9)) ||
(mt9m001->datawidth != 8 && (width_flag == IS_DATAWIDTH_8))) { (mt9m001->datawidth != 8 && (width_flag == SOCAM_DATAWIDTH_8))) {
/* Well, we actually only can do 10 or 8 bits... */ /* Well, we actually only can do 10 or 8 bits... */
if (width_flag == IS_DATAWIDTH_9) if (width_flag == SOCAM_DATAWIDTH_9)
return -EINVAL; return -EINVAL;
ret = bus_switch_act(mt9m001, ret = bus_switch_act(mt9m001,
width_flag == IS_DATAWIDTH_8); width_flag == SOCAM_DATAWIDTH_8);
if (ret < 0) if (ret < 0)
return ret; return ret;
mt9m001->datawidth = width_flag == IS_DATAWIDTH_8 ? 8 : 10; mt9m001->datawidth = width_flag == SOCAM_DATAWIDTH_8 ? 8 : 10;
} }
return 0;
}
static unsigned long mt9m001_query_bus_param(struct soc_camera_device *icd)
{
struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
unsigned int width_flag = SOCAM_DATAWIDTH_10;
if (bus_switch_possible(mt9m001))
width_flag |= SOCAM_DATAWIDTH_8;
/* MT9M001 has all capture_format parameters fixed */
return SOCAM_PCLK_SAMPLE_RISING |
SOCAM_HSYNC_ACTIVE_HIGH |
SOCAM_VSYNC_ACTIVE_HIGH |
SOCAM_MASTER |
width_flag;
}
static int mt9m001_set_fmt_cap(struct soc_camera_device *icd,
__u32 pixfmt, struct v4l2_rect *rect)
{
struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
int ret;
const u16 hblank = 9, vblank = 25;
/* Blanking and start values - default... */ /* Blanking and start values - default... */
ret = reg_write(icd, MT9M001_HORIZONTAL_BLANKING, hblank); ret = reg_write(icd, MT9M001_HORIZONTAL_BLANKING, hblank);
if (ret >= 0) if (ret >= 0)
...@@ -348,12 +372,6 @@ static int mt9m001_set_register(struct soc_camera_device *icd, ...@@ -348,12 +372,6 @@ static int mt9m001_set_register(struct soc_camera_device *icd,
} }
#endif #endif
static unsigned int mt9m001_get_datawidth(struct soc_camera_device *icd)
{
struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
return mt9m001->datawidth;
}
const struct v4l2_queryctrl mt9m001_controls[] = { const struct v4l2_queryctrl mt9m001_controls[] = {
{ {
.id = V4L2_CID_VFLIP, .id = V4L2_CID_VFLIP,
...@@ -401,11 +419,12 @@ static struct soc_camera_ops mt9m001_ops = { ...@@ -401,11 +419,12 @@ static struct soc_camera_ops mt9m001_ops = {
.release = mt9m001_release, .release = mt9m001_release,
.start_capture = mt9m001_start_capture, .start_capture = mt9m001_start_capture,
.stop_capture = mt9m001_stop_capture, .stop_capture = mt9m001_stop_capture,
.set_capture_format = mt9m001_set_capture_format, .set_fmt_cap = mt9m001_set_fmt_cap,
.try_fmt_cap = mt9m001_try_fmt_cap, .try_fmt_cap = mt9m001_try_fmt_cap,
.set_bus_param = mt9m001_set_bus_param,
.query_bus_param = mt9m001_query_bus_param,
.formats = NULL, /* Filled in later depending on the */ .formats = NULL, /* Filled in later depending on the */
.num_formats = 0, /* camera type and data widths */ .num_formats = 0, /* camera type and data widths */
.get_datawidth = mt9m001_get_datawidth,
.controls = mt9m001_controls, .controls = mt9m001_controls,
.num_controls = ARRAY_SIZE(mt9m001_controls), .num_controls = ARRAY_SIZE(mt9m001_controls),
.get_control = mt9m001_get_control, .get_control = mt9m001_get_control,
......
...@@ -241,19 +241,89 @@ static int bus_switch_act(struct mt9v022 *mt9v022, int go8bit) ...@@ -241,19 +241,89 @@ static int bus_switch_act(struct mt9v022 *mt9v022, int go8bit)
#endif #endif
} }
static int mt9v022_set_capture_format(struct soc_camera_device *icd, static int bus_switch_possible(struct mt9v022 *mt9v022)
__u32 pixfmt, struct v4l2_rect *rect, unsigned int flags) {
#ifdef CONFIG_MT9V022_PCA9536_SWITCH
return gpio_is_valid(mt9v022->switch_gpio);
#else
return 0;
#endif
}
static int mt9v022_set_bus_param(struct soc_camera_device *icd,
unsigned long flags)
{ {
struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd); struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
unsigned int width_flag = flags & (IS_DATAWIDTH_10 | IS_DATAWIDTH_9 | unsigned int width_flag = flags & SOCAM_DATAWIDTH_MASK;
IS_DATAWIDTH_8);
u16 pixclk = 0;
int ret; int ret;
u16 pixclk = 0;
/* Only one width bit may be set */ /* Only one width bit may be set */
if (!is_power_of_2(width_flag)) if (!is_power_of_2(width_flag))
return -EINVAL; return -EINVAL;
if ((mt9v022->datawidth != 10 && (width_flag == SOCAM_DATAWIDTH_10)) ||
(mt9v022->datawidth != 9 && (width_flag == SOCAM_DATAWIDTH_9)) ||
(mt9v022->datawidth != 8 && (width_flag == SOCAM_DATAWIDTH_8))) {
/* Well, we actually only can do 10 or 8 bits... */
if (width_flag == SOCAM_DATAWIDTH_9)
return -EINVAL;
ret = bus_switch_act(mt9v022,
width_flag == SOCAM_DATAWIDTH_8);
if (ret < 0)
return ret;
mt9v022->datawidth = width_flag == SOCAM_DATAWIDTH_8 ? 8 : 10;
}
if (flags & SOCAM_PCLK_SAMPLE_RISING)
pixclk |= 0x10;
if (!(flags & SOCAM_HSYNC_ACTIVE_HIGH))
pixclk |= 0x1;
if (!(flags & SOCAM_VSYNC_ACTIVE_HIGH))
pixclk |= 0x2;
ret = reg_write(icd, MT9V022_PIXCLK_FV_LV, pixclk);
if (ret < 0)
return ret;
if (!(flags & SOCAM_MASTER))
mt9v022->chip_control &= ~0x8;
ret = reg_write(icd, MT9V022_CHIP_CONTROL, mt9v022->chip_control);
if (ret < 0)
return ret;
dev_dbg(&icd->dev, "Calculated pixclk 0x%x, chip control 0x%x\n",
pixclk, mt9v022->chip_control);
return 0;
}
static unsigned long mt9v022_query_bus_param(struct soc_camera_device *icd)
{
struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
unsigned int width_flag = SOCAM_DATAWIDTH_10;
if (bus_switch_possible(mt9v022))
width_flag |= SOCAM_DATAWIDTH_8;
return SOCAM_PCLK_SAMPLE_RISING | SOCAM_PCLK_SAMPLE_FALLING |
SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_LOW |
SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_LOW |
SOCAM_MASTER | SOCAM_SLAVE |
width_flag;
}
static int mt9v022_set_fmt_cap(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 /* 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_cap(), datawidth is from our supported format list */
switch (pixfmt) { switch (pixfmt) {
...@@ -308,44 +378,6 @@ static int mt9v022_set_capture_format(struct soc_camera_device *icd, ...@@ -308,44 +378,6 @@ static int mt9v022_set_capture_format(struct soc_camera_device *icd,
dev_dbg(&icd->dev, "Frame %ux%u pixel\n", rect->width, rect->height); dev_dbg(&icd->dev, "Frame %ux%u pixel\n", rect->width, rect->height);
if ((mt9v022->datawidth != 10 && (width_flag == IS_DATAWIDTH_10)) ||
(mt9v022->datawidth != 9 && (width_flag == IS_DATAWIDTH_9)) ||
(mt9v022->datawidth != 8 && (width_flag == IS_DATAWIDTH_8))) {
/* Well, we actually only can do 10 or 8 bits... */
if (width_flag == IS_DATAWIDTH_9)
return -EINVAL;
ret = bus_switch_act(mt9v022,
width_flag == IS_DATAWIDTH_8);
if (ret < 0)
return ret;
mt9v022->datawidth = width_flag == IS_DATAWIDTH_8 ? 8 : 10;
}
if (flags & IS_PCLK_SAMPLE_RISING)
pixclk |= 0x10;
if (!(flags & IS_HSYNC_ACTIVE_HIGH))
pixclk |= 0x1;
if (!(flags & IS_VSYNC_ACTIVE_HIGH))
pixclk |= 0x2;
ret = reg_write(icd, MT9V022_PIXCLK_FV_LV, pixclk);
if (ret < 0)
return ret;
if (!(flags & IS_MASTER))
mt9v022->chip_control &= ~0x8;
ret = reg_write(icd, MT9V022_CHIP_CONTROL, mt9v022->chip_control);
if (ret < 0)
return ret;
dev_dbg(&icd->dev, "Calculated pixclk 0x%x, chip control 0x%x\n",
pixclk, mt9v022->chip_control);
return 0; return 0;
} }
...@@ -420,12 +452,6 @@ static int mt9v022_set_register(struct soc_camera_device *icd, ...@@ -420,12 +452,6 @@ static int mt9v022_set_register(struct soc_camera_device *icd,
} }
#endif #endif
static unsigned int mt9v022_get_datawidth(struct soc_camera_device *icd)
{
struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
return mt9v022->datawidth;
}
const struct v4l2_queryctrl mt9v022_controls[] = { const struct v4l2_queryctrl mt9v022_controls[] = {
{ {
.id = V4L2_CID_VFLIP, .id = V4L2_CID_VFLIP,
...@@ -491,11 +517,12 @@ static struct soc_camera_ops mt9v022_ops = { ...@@ -491,11 +517,12 @@ static struct soc_camera_ops mt9v022_ops = {
.release = mt9v022_release, .release = mt9v022_release,
.start_capture = mt9v022_start_capture, .start_capture = mt9v022_start_capture,
.stop_capture = mt9v022_stop_capture, .stop_capture = mt9v022_stop_capture,
.set_capture_format = mt9v022_set_capture_format, .set_fmt_cap = mt9v022_set_fmt_cap,
.try_fmt_cap = mt9v022_try_fmt_cap, .try_fmt_cap = mt9v022_try_fmt_cap,
.set_bus_param = mt9v022_set_bus_param,
.query_bus_param = mt9v022_query_bus_param,
.formats = NULL, /* Filled in later depending on the */ .formats = NULL, /* Filled in later depending on the */
.num_formats = 0, /* sensor type and data widths */ .num_formats = 0, /* sensor type and data widths */
.get_datawidth = mt9v022_get_datawidth,
.controls = mt9v022_controls, .controls = mt9v022_controls,
.num_controls = ARRAY_SIZE(mt9v022_controls), .num_controls = ARRAY_SIZE(mt9v022_controls),
.get_control = mt9v022_get_control, .get_control = mt9v022_get_control,
......
...@@ -581,64 +581,109 @@ static void pxa_camera_remove_device(struct soc_camera_device *icd) ...@@ -581,64 +581,109 @@ static void pxa_camera_remove_device(struct soc_camera_device *icd)
pcdev->icd = NULL; pcdev->icd = NULL;
} }
static int pxa_camera_set_capture_format(struct soc_camera_device *icd, static int test_platform_param(struct pxa_camera_dev *pcdev,
__u32 pixfmt, struct v4l2_rect *rect) unsigned char buswidth, unsigned long *flags)
{ {
struct soc_camera_host *ici = /*
to_soc_camera_host(icd->dev.parent); * Platform specified synchronization and pixel clock polarities are
struct pxa_camera_dev *pcdev = ici->priv; * only a recommendation and are only used during probing. The PXA270
unsigned int datawidth = 0, dw, bpp; * quick capture interface supports both.
u32 cicr0, cicr4 = 0; */
int ret; *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 */ /* If requested data width is supported by the platform, use it */
switch (icd->cached_datawidth) { switch (buswidth) {
case 10: case 10:
if (pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_10) if (!(pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_10))
datawidth = IS_DATAWIDTH_10; return -EINVAL;
*flags |= SOCAM_DATAWIDTH_10;
break; break;
case 9: case 9:
if (pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_9) if (!(pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_9))
datawidth = IS_DATAWIDTH_9; return -EINVAL;
*flags |= SOCAM_DATAWIDTH_9;
break; break;
case 8: case 8:
if (pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_8) if (!(pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_8))
datawidth = IS_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; return -EINVAL;
ret = icd->ops->set_capture_format(icd, pixfmt, rect, /* Make choises, based on platform preferences */
datawidth | if ((common_flags & SOCAM_HSYNC_ACTIVE_HIGH) &&
(pcdev->platform_flags & PXA_CAMERA_MASTER ? (common_flags & SOCAM_HSYNC_ACTIVE_LOW)) {
IS_MASTER : 0) | if (pcdev->platform_flags & PXA_CAMERA_HSP)
(pcdev->platform_flags & PXA_CAMERA_HSP ? common_flags &= ~SOCAM_HSYNC_ACTIVE_HIGH;
0 : IS_HSYNC_ACTIVE_HIGH) | else
(pcdev->platform_flags & PXA_CAMERA_VSP ? common_flags &= ~SOCAM_HSYNC_ACTIVE_LOW;
0 : IS_VSYNC_ACTIVE_HIGH) | }
(pcdev->platform_flags & PXA_CAMERA_PCP ?
0 : IS_PCLK_SAMPLE_RISING)); 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) if (ret < 0)
return ret; return ret;
/* Datawidth is now guaranteed to be equal to one of the three values. /* Datawidth is now guaranteed to be equal to one of the three values.
* We fix bit-per-pixel equal to data-width... */ * We fix bit-per-pixel equal to data-width... */
switch (datawidth) { switch (common_flags & SOCAM_DATAWIDTH_MASK) {
case IS_DATAWIDTH_10: case SOCAM_DATAWIDTH_10:
icd->cached_datawidth = 10; icd->buswidth = 10;
dw = 4; dw = 4;
bpp = 0x40; bpp = 0x40;
break; break;
case IS_DATAWIDTH_9: case SOCAM_DATAWIDTH_9:
icd->cached_datawidth = 9; icd->buswidth = 9;
dw = 3; dw = 3;
bpp = 0x20; bpp = 0x20;
break; break;
default: default:
/* Actually it can only be 8 now, /* Actually it can only be 8 now,
* default is just to silence compiler warnings */ * default is just to silence compiler warnings */
case IS_DATAWIDTH_8: case SOCAM_DATAWIDTH_8:
icd->cached_datawidth = 8; icd->buswidth = 8;
dw = 2; dw = 2;
bpp = 0; bpp = 0;
} }
...@@ -647,19 +692,19 @@ static int pxa_camera_set_capture_format(struct soc_camera_device *icd, ...@@ -647,19 +692,19 @@ static int pxa_camera_set_capture_format(struct soc_camera_device *icd,
cicr4 |= CICR4_PCLK_EN; cicr4 |= CICR4_PCLK_EN;
if (pcdev->platform_flags & PXA_CAMERA_MCLK_EN) if (pcdev->platform_flags & PXA_CAMERA_MCLK_EN)
cicr4 |= CICR4_MCLK_EN; cicr4 |= CICR4_MCLK_EN;
if (pcdev->platform_flags & PXA_CAMERA_PCP) if (common_flags & SOCAM_PCLK_SAMPLE_FALLING)
cicr4 |= CICR4_PCP; cicr4 |= CICR4_PCP;
if (pcdev->platform_flags & PXA_CAMERA_HSP) if (common_flags & SOCAM_HSYNC_ACTIVE_LOW)
cicr4 |= CICR4_HSP; cicr4 |= CICR4_HSP;
if (pcdev->platform_flags & PXA_CAMERA_VSP) if (common_flags & SOCAM_VSYNC_ACTIVE_LOW)
cicr4 |= CICR4_VSP; cicr4 |= CICR4_VSP;
cicr0 = CICR0; cicr0 = CICR0;
if (cicr0 & CICR0_ENB) if (cicr0 & CICR0_ENB)
CICR0 = 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; 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)); CICR3_BFW_VAL(min((unsigned short)255, icd->y_skip_top));
CICR4 = mclk_get_divisor(pcdev) | cicr4; CICR4 = mclk_get_divisor(pcdev) | cicr4;
...@@ -671,7 +716,29 @@ static int pxa_camera_set_capture_format(struct soc_camera_device *icd, ...@@ -671,7 +716,29 @@ static int pxa_camera_set_capture_format(struct soc_camera_device *icd,
return 0; 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) struct v4l2_format *f)
{ {
/* limit to pxa hardware capabilities */ /* limit to pxa hardware capabilities */
...@@ -685,7 +752,8 @@ static int pxa_camera_try_fmt_cap(struct soc_camera_host *ici, ...@@ -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 = 2048;
f->fmt.pix.width &= ~0x01; 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, static int pxa_camera_reqbufs(struct soc_camera_file *icf,
...@@ -742,11 +810,13 @@ static struct soc_camera_host pxa_soc_camera_host = { ...@@ -742,11 +810,13 @@ static struct soc_camera_host pxa_soc_camera_host = {
.add = pxa_camera_add_device, .add = pxa_camera_add_device,
.remove = pxa_camera_remove_device, .remove = pxa_camera_remove_device,
.msize = sizeof(struct pxa_buffer), .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, .try_fmt_cap = pxa_camera_try_fmt_cap,
.reqbufs = pxa_camera_reqbufs, .reqbufs = pxa_camera_reqbufs,
.poll = pxa_camera_poll, .poll = pxa_camera_poll,
.querycap = pxa_camera_querycap, .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) static int pxa_camera_probe(struct platform_device *pdev)
...@@ -782,8 +852,8 @@ 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->pdata = pdev->dev.platform_data;
pcdev->platform_flags = pcdev->pdata->flags; pcdev->platform_flags = pcdev->pdata->flags;
if (!pcdev->platform_flags & (PXA_CAMERA_DATAWIDTH_8 | if (!(pcdev->platform_flags & (PXA_CAMERA_DATAWIDTH_8 |
PXA_CAMERA_DATAWIDTH_9 | PXA_CAMERA_DATAWIDTH_10)) { PXA_CAMERA_DATAWIDTH_9 | PXA_CAMERA_DATAWIDTH_10))) {
/* Platform hasn't set available data widths. This is bad. /* Platform hasn't set available data widths. This is bad.
* Warn and use a default. */ * Warn and use a default. */
dev_warn(&pdev->dev, "WARNING! Platform hasn't set available " dev_warn(&pdev->dev, "WARNING! Platform hasn't set available "
......
...@@ -75,12 +75,13 @@ static int soc_camera_try_fmt_cap(struct file *file, void *priv, ...@@ -75,12 +75,13 @@ static int soc_camera_try_fmt_cap(struct file *file, void *priv,
return -EINVAL; return -EINVAL;
} }
/* limit to host capabilities */ /* test physical bus parameters */
ret = ici->try_fmt_cap(ici, f); ret = ici->try_bus_param(icd, f->fmt.pix.pixelformat);
if (ret)
return ret;
/* limit to sensor capabilities */ /* limit format to hardware capabilities */
if (!ret) ret = ici->try_fmt_cap(icd, f);
ret = icd->ops->try_fmt_cap(icd, f);
/* calculate missing fields */ /* calculate missing fields */
f->fmt.pix.field = field; f->fmt.pix.field = field;
...@@ -344,8 +345,8 @@ static int soc_camera_s_fmt_cap(struct file *file, void *priv, ...@@ -344,8 +345,8 @@ static int soc_camera_s_fmt_cap(struct file *file, void *priv,
if (!data_fmt) if (!data_fmt)
return -EINVAL; return -EINVAL;
/* cached_datawidth may be further adjusted by the ici */ /* buswidth may be further adjusted by the ici */
icd->cached_datawidth = data_fmt->depth; icd->buswidth = data_fmt->depth;
ret = soc_camera_try_fmt_cap(file, icf, f); ret = soc_camera_try_fmt_cap(file, icf, f);
if (ret < 0) if (ret < 0)
...@@ -355,9 +356,10 @@ static int soc_camera_s_fmt_cap(struct file *file, void *priv, ...@@ -355,9 +356,10 @@ static int soc_camera_s_fmt_cap(struct file *file, void *priv,
rect.top = icd->y_current; rect.top = icd->y_current;
rect.width = f->fmt.pix.width; rect.width = f->fmt.pix.width;
rect.height = f->fmt.pix.height; rect.height = f->fmt.pix.height;
ret = ici->set_capture_format(icd, f->fmt.pix.pixelformat, &rect); ret = ici->set_fmt_cap(icd, f->fmt.pix.pixelformat, &rect);
if (ret < 0)
return ret;
if (!ret) {
icd->current_fmt = data_fmt; icd->current_fmt = data_fmt;
icd->width = rect.width; icd->width = rect.width;
icd->height = rect.height; icd->height = rect.height;
...@@ -368,9 +370,9 @@ static int soc_camera_s_fmt_cap(struct file *file, void *priv, ...@@ -368,9 +370,9 @@ static int soc_camera_s_fmt_cap(struct file *file, void *priv,
dev_dbg(&icd->dev, "set width: %d height: %d\n", dev_dbg(&icd->dev, "set width: %d height: %d\n",
icd->width, icd->height); icd->width, icd->height);
}
return ret; /* set physical bus parameters */
return ici->set_bus_param(icd, f->fmt.pix.pixelformat);
} }
static int soc_camera_enum_fmt_cap(struct file *file, void *priv, static int soc_camera_enum_fmt_cap(struct file *file, void *priv,
...@@ -577,7 +579,7 @@ static int soc_camera_s_crop(struct file *file, void *fh, ...@@ -577,7 +579,7 @@ static int soc_camera_s_crop(struct file *file, void *fh,
if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL; return -EINVAL;
ret = ici->set_capture_format(icd, 0, &a->c); ret = ici->set_fmt_cap(icd, 0, &a->c);
if (!ret) { if (!ret) {
icd->width = a->c.width; icd->width = a->c.width;
icd->height = a->c.height; icd->height = a->c.height;
...@@ -860,9 +862,6 @@ int soc_camera_device_register(struct soc_camera_device *icd) ...@@ -860,9 +862,6 @@ int soc_camera_device_register(struct soc_camera_device *icd)
icd->dev.release = dummy_release; icd->dev.release = dummy_release;
if (icd->ops->get_datawidth)
icd->cached_datawidth = icd->ops->get_datawidth(icd);
return scan_add_device(icd); return scan_add_device(icd);
} }
EXPORT_SYMBOL(soc_camera_device_register); EXPORT_SYMBOL(soc_camera_device_register);
......
...@@ -34,7 +34,7 @@ struct soc_camera_device { ...@@ -34,7 +34,7 @@ struct soc_camera_device {
unsigned short exposure; unsigned short exposure;
unsigned char iface; /* Host number */ unsigned char iface; /* Host number */
unsigned char devnum; /* Device number per host */ unsigned char devnum; /* Device number per host */
unsigned char cached_datawidth; /* See comment in .c */ unsigned char buswidth; /* See comment in .c */
struct soc_camera_ops *ops; struct soc_camera_ops *ops;
struct video_device *vdev; struct video_device *vdev;
const struct soc_camera_data_format *current_fmt; const struct soc_camera_data_format *current_fmt;
...@@ -61,11 +61,13 @@ struct soc_camera_host { ...@@ -61,11 +61,13 @@ struct soc_camera_host {
char *drv_name; char *drv_name;
int (*add)(struct soc_camera_device *); int (*add)(struct soc_camera_device *);
void (*remove)(struct soc_camera_device *); void (*remove)(struct soc_camera_device *);
int (*set_capture_format)(struct soc_camera_device *, __u32, int (*set_fmt_cap)(struct soc_camera_device *, __u32,
struct v4l2_rect *); struct v4l2_rect *);
int (*try_fmt_cap)(struct soc_camera_host *, struct v4l2_format *); int (*try_fmt_cap)(struct soc_camera_device *, struct v4l2_format *);
int (*reqbufs)(struct soc_camera_file *, struct v4l2_requestbuffers *); int (*reqbufs)(struct soc_camera_file *, struct v4l2_requestbuffers *);
int (*querycap)(struct soc_camera_host *, struct v4l2_capability *); 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 *); unsigned int (*poll)(struct file *, poll_table *);
}; };
...@@ -108,9 +110,11 @@ struct soc_camera_ops { ...@@ -108,9 +110,11 @@ struct soc_camera_ops {
int (*release)(struct soc_camera_device *); int (*release)(struct soc_camera_device *);
int (*start_capture)(struct soc_camera_device *); int (*start_capture)(struct soc_camera_device *);
int (*stop_capture)(struct soc_camera_device *); int (*stop_capture)(struct soc_camera_device *);
int (*set_capture_format)(struct soc_camera_device *, __u32, int (*set_fmt_cap)(struct soc_camera_device *, __u32,
struct v4l2_rect *, unsigned int); struct v4l2_rect *);
int (*try_fmt_cap)(struct soc_camera_device *, struct v4l2_format *); int (*try_fmt_cap)(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 *, int (*get_chip_id)(struct soc_camera_device *,
struct v4l2_chip_ident *); struct v4l2_chip_ident *);
#ifdef CONFIG_VIDEO_ADV_DEBUG #ifdef CONFIG_VIDEO_ADV_DEBUG
...@@ -123,7 +127,6 @@ struct soc_camera_ops { ...@@ -123,7 +127,6 @@ struct soc_camera_ops {
int (*set_control)(struct soc_camera_device *, struct v4l2_control *); int (*set_control)(struct soc_camera_device *, struct v4l2_control *);
const struct v4l2_queryctrl *controls; const struct v4l2_queryctrl *controls;
int num_controls; int num_controls;
unsigned int(*get_datawidth)(struct soc_camera_device *icd);
}; };
static inline struct v4l2_queryctrl const *soc_camera_find_qctrl( static inline struct v4l2_queryctrl const *soc_camera_find_qctrl(
...@@ -138,12 +141,33 @@ static inline struct v4l2_queryctrl const *soc_camera_find_qctrl( ...@@ -138,12 +141,33 @@ static inline struct v4l2_queryctrl const *soc_camera_find_qctrl(
return NULL; return NULL;
} }
#define IS_MASTER (1<<0) #define SOCAM_MASTER (1 << 0)
#define IS_HSYNC_ACTIVE_HIGH (1<<1) #define SOCAM_SLAVE (1 << 1)
#define IS_VSYNC_ACTIVE_HIGH (1<<2) #define SOCAM_HSYNC_ACTIVE_HIGH (1 << 2)
#define IS_DATAWIDTH_8 (1<<3) #define SOCAM_HSYNC_ACTIVE_LOW (1 << 3)
#define IS_DATAWIDTH_9 (1<<4) #define SOCAM_VSYNC_ACTIVE_HIGH (1 << 4)
#define IS_DATAWIDTH_10 (1<<5) #define SOCAM_VSYNC_ACTIVE_LOW (1 << 5)
#define IS_PCLK_SAMPLE_RISING (1<<6) #define SOCAM_DATAWIDTH_8 (1 << 6)
#define SOCAM_DATAWIDTH_9 (1 << 7)
#define SOCAM_DATAWIDTH_10 (1 << 8)
#define SOCAM_PCLK_SAMPLE_RISING (1 << 9)
#define SOCAM_PCLK_SAMPLE_FALLING (1 << 10)
#define SOCAM_DATAWIDTH_MASK (SOCAM_DATAWIDTH_8 | SOCAM_DATAWIDTH_9 | \
SOCAM_DATAWIDTH_10)
static inline unsigned long soc_camera_bus_param_compatible(
unsigned long camera_flags, unsigned long bus_flags)
{
unsigned long common_flags, hsync, vsync, pclk;
common_flags = camera_flags & bus_flags;
hsync = common_flags & (SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_LOW);
vsync = common_flags & (SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_LOW);
pclk = common_flags & (SOCAM_PCLK_SAMPLE_RISING | SOCAM_PCLK_SAMPLE_FALLING);
return (!hsync || !vsync || !pclk) ? 0 : common_flags;
}
#endif #endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment