Skip to content

Commit

Permalink
V4L/DVB (7336): soc-camera: streamline hardware parameter negotiation
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Guennadi Liakhovetski authored and Mauro Carvalho Chehab committed Apr 24, 2008
1 parent 1c65968 commit ad5f2e8
Show file tree
Hide file tree
Showing 5 changed files with 301 additions and 162 deletions.
77 changes: 48 additions & 29 deletions drivers/media/video/mt9m001.c
Original file line number Diff line number Diff line change
Expand Up @@ -210,40 +210,64 @@ static int bus_switch_act(struct mt9m001 *mt9m001, int go8bit)
#endif
}

static int mt9m001_set_capture_format(struct soc_camera_device *icd,
__u32 pixfmt, struct v4l2_rect *rect, unsigned int flags)
static int bus_switch_possible(struct mt9m001 *mt9m001)
{
#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);
unsigned int width_flag = flags & (IS_DATAWIDTH_10 | IS_DATAWIDTH_9 |
IS_DATAWIDTH_8);
unsigned int width_flag = flags & SOCAM_DATAWIDTH_MASK;
int ret;
const u16 hblank = 9, vblank = 25;

/* MT9M001 has all capture_format parameters fixed */
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;
/* Flags validity verified in test_bus_param */

if ((mt9m001->datawidth != 10 && (width_flag == IS_DATAWIDTH_10)) ||
(mt9m001->datawidth != 9 && (width_flag == IS_DATAWIDTH_9)) ||
(mt9m001->datawidth != 8 && (width_flag == IS_DATAWIDTH_8))) {
if ((mt9m001->datawidth != 10 && (width_flag == SOCAM_DATAWIDTH_10)) ||
(mt9m001->datawidth != 9 && (width_flag == SOCAM_DATAWIDTH_9)) ||
(mt9m001->datawidth != 8 && (width_flag == SOCAM_DATAWIDTH_8))) {
/* Well, we actually only can do 10 or 8 bits... */
if (width_flag == IS_DATAWIDTH_9)
if (width_flag == SOCAM_DATAWIDTH_9)
return -EINVAL;
ret = bus_switch_act(mt9m001,
width_flag == IS_DATAWIDTH_8);
width_flag == SOCAM_DATAWIDTH_8);
if (ret < 0)
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... */
ret = reg_write(icd, MT9M001_HORIZONTAL_BLANKING, hblank);
if (ret >= 0)
Expand Down Expand Up @@ -348,12 +372,6 @@ static int mt9m001_set_register(struct soc_camera_device *icd,
}
#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[] = {
{
.id = V4L2_CID_VFLIP,
Expand Down Expand Up @@ -401,11 +419,12 @@ static struct soc_camera_ops mt9m001_ops = {
.release = mt9m001_release,
.start_capture = mt9m001_start_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,
.set_bus_param = mt9m001_set_bus_param,
.query_bus_param = mt9m001_query_bus_param,
.formats = NULL, /* Filled in later depending on the */
.num_formats = 0, /* camera type and data widths */
.get_datawidth = mt9m001_get_datawidth,
.controls = mt9m001_controls,
.num_controls = ARRAY_SIZE(mt9m001_controls),
.get_control = mt9m001_get_control,
Expand Down
129 changes: 78 additions & 51 deletions drivers/media/video/mt9v022.c
Original file line number Diff line number Diff line change
Expand Up @@ -241,19 +241,89 @@ static int bus_switch_act(struct mt9v022 *mt9v022, int go8bit)
#endif
}

static int mt9v022_set_capture_format(struct soc_camera_device *icd,
__u32 pixfmt, struct v4l2_rect *rect, unsigned int flags)
static int bus_switch_possible(struct mt9v022 *mt9v022)
{
#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);
unsigned int width_flag = flags & (IS_DATAWIDTH_10 | IS_DATAWIDTH_9 |
IS_DATAWIDTH_8);
u16 pixclk = 0;
unsigned int width_flag = flags & SOCAM_DATAWIDTH_MASK;
int ret;
u16 pixclk = 0;

/* Only one width bit may be set */
if (!is_power_of_2(width_flag))
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
* icd->try_fmt_cap(), datawidth is from our supported format list */
switch (pixfmt) {
Expand Down Expand Up @@ -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);

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;
}

Expand Down Expand Up @@ -420,12 +452,6 @@ static int mt9v022_set_register(struct soc_camera_device *icd,
}
#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[] = {
{
.id = V4L2_CID_VFLIP,
Expand Down Expand Up @@ -491,11 +517,12 @@ static struct soc_camera_ops mt9v022_ops = {
.release = mt9v022_release,
.start_capture = mt9v022_start_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,
.set_bus_param = mt9v022_set_bus_param,
.query_bus_param = mt9v022_query_bus_param,
.formats = NULL, /* Filled in later depending on the */
.num_formats = 0, /* sensor type and data widths */
.get_datawidth = mt9v022_get_datawidth,
.controls = mt9v022_controls,
.num_controls = ARRAY_SIZE(mt9v022_controls),
.get_control = mt9v022_get_control,
Expand Down
Loading

0 comments on commit ad5f2e8

Please sign in to comment.