V4L/DVB (11024): soc-camera: separate S_FMT and S_CROP operations
As host and camera drivers become more complex, differences between S_FMT and S_CROP functionality grow, this patch separates them. Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
This commit is contained in:
parent
1cd3c0fa92
commit
09e231b351
@ -284,8 +284,8 @@ static unsigned long mt9m001_query_bus_param(struct soc_camera_device *icd)
|
||||
return soc_camera_apply_sensor_flags(icl, flags);
|
||||
}
|
||||
|
||||
static int mt9m001_set_fmt(struct soc_camera_device *icd,
|
||||
__u32 pixfmt, struct v4l2_rect *rect)
|
||||
static int mt9m001_set_crop(struct soc_camera_device *icd,
|
||||
struct v4l2_rect *rect)
|
||||
{
|
||||
struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
|
||||
int ret;
|
||||
@ -324,6 +324,20 @@ static int mt9m001_set_fmt(struct soc_camera_device *icd,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mt9m001_set_fmt(struct soc_camera_device *icd,
|
||||
struct v4l2_format *f)
|
||||
{
|
||||
struct v4l2_rect rect = {
|
||||
.left = icd->x_current,
|
||||
.top = icd->y_current,
|
||||
.width = f->fmt.pix.width,
|
||||
.height = f->fmt.pix.height,
|
||||
};
|
||||
|
||||
/* No support for scaling so far, just crop. TODO: use skipping */
|
||||
return mt9m001_set_crop(icd, &rect);
|
||||
}
|
||||
|
||||
static int mt9m001_try_fmt(struct soc_camera_device *icd,
|
||||
struct v4l2_format *f)
|
||||
{
|
||||
@ -449,6 +463,7 @@ static struct soc_camera_ops mt9m001_ops = {
|
||||
.release = mt9m001_release,
|
||||
.start_capture = mt9m001_start_capture,
|
||||
.stop_capture = mt9m001_stop_capture,
|
||||
.set_crop = mt9m001_set_crop,
|
||||
.set_fmt = mt9m001_set_fmt,
|
||||
.try_fmt = mt9m001_try_fmt,
|
||||
.set_bus_param = mt9m001_set_bus_param,
|
||||
|
@ -152,7 +152,7 @@ struct mt9m111 {
|
||||
struct soc_camera_device icd;
|
||||
int model; /* V4L2_IDENT_MT9M11x* codes from v4l2-chip-ident.h */
|
||||
enum mt9m111_context context;
|
||||
unsigned int left, top, width, height;
|
||||
struct v4l2_rect rect;
|
||||
u32 pixfmt;
|
||||
unsigned char autoexposure;
|
||||
unsigned char datawidth;
|
||||
@ -249,12 +249,13 @@ static int mt9m111_set_context(struct soc_camera_device *icd,
|
||||
return reg_write(CONTEXT_CONTROL, valA);
|
||||
}
|
||||
|
||||
static int mt9m111_setup_rect(struct soc_camera_device *icd)
|
||||
static int mt9m111_setup_rect(struct soc_camera_device *icd,
|
||||
struct v4l2_rect *rect)
|
||||
{
|
||||
struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
|
||||
int ret, is_raw_format;
|
||||
int width = mt9m111->width;
|
||||
int height = mt9m111->height;
|
||||
int width = rect->width;
|
||||
int height = rect->height;
|
||||
|
||||
if ((mt9m111->pixfmt == V4L2_PIX_FMT_SBGGR8)
|
||||
|| (mt9m111->pixfmt == V4L2_PIX_FMT_SBGGR16))
|
||||
@ -262,9 +263,9 @@ static int mt9m111_setup_rect(struct soc_camera_device *icd)
|
||||
else
|
||||
is_raw_format = 0;
|
||||
|
||||
ret = reg_write(COLUMN_START, mt9m111->left);
|
||||
ret = reg_write(COLUMN_START, rect->left);
|
||||
if (!ret)
|
||||
ret = reg_write(ROW_START, mt9m111->top);
|
||||
ret = reg_write(ROW_START, rect->top);
|
||||
|
||||
if (is_raw_format) {
|
||||
if (!ret)
|
||||
@ -436,6 +437,22 @@ static int mt9m111_set_bus_param(struct soc_camera_device *icd, unsigned long f)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mt9m111_set_crop(struct soc_camera_device *icd,
|
||||
struct v4l2_rect *rect)
|
||||
{
|
||||
struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
|
||||
int ret;
|
||||
|
||||
dev_dbg(&icd->dev, "%s left=%d, top=%d, width=%d, height=%d\n",
|
||||
__func__, rect->left, rect->top, rect->width,
|
||||
rect->height);
|
||||
|
||||
ret = mt9m111_setup_rect(icd, rect);
|
||||
if (!ret)
|
||||
mt9m111->rect = *rect;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mt9m111_set_pixfmt(struct soc_camera_device *icd, u32 pixfmt)
|
||||
{
|
||||
struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
|
||||
@ -486,23 +503,27 @@ static int mt9m111_set_pixfmt(struct soc_camera_device *icd, u32 pixfmt)
|
||||
}
|
||||
|
||||
static int mt9m111_set_fmt(struct soc_camera_device *icd,
|
||||
__u32 pixfmt, struct v4l2_rect *rect)
|
||||
struct v4l2_format *f)
|
||||
{
|
||||
struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
|
||||
struct v4l2_pix_format *pix = &f->fmt.pix;
|
||||
struct v4l2_rect rect = {
|
||||
.left = mt9m111->rect.left,
|
||||
.top = mt9m111->rect.top,
|
||||
.width = pix->width,
|
||||
.height = pix->height,
|
||||
};
|
||||
int ret;
|
||||
|
||||
mt9m111->left = rect->left;
|
||||
mt9m111->top = rect->top;
|
||||
mt9m111->width = rect->width;
|
||||
mt9m111->height = rect->height;
|
||||
|
||||
dev_dbg(&icd->dev, "%s fmt=%x left=%d, top=%d, width=%d, height=%d\n",
|
||||
__func__, pixfmt, mt9m111->left, mt9m111->top, mt9m111->width,
|
||||
mt9m111->height);
|
||||
__func__, pix->pixelformat, rect.left, rect.top, rect.width,
|
||||
rect.height);
|
||||
|
||||
ret = mt9m111_setup_rect(icd);
|
||||
ret = mt9m111_setup_rect(icd, &rect);
|
||||
if (!ret)
|
||||
ret = mt9m111_set_pixfmt(icd, pixfmt);
|
||||
ret = mt9m111_set_pixfmt(icd, pix->pixelformat);
|
||||
if (!ret)
|
||||
mt9m111->rect = rect;
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -633,6 +654,7 @@ static struct soc_camera_ops mt9m111_ops = {
|
||||
.release = mt9m111_release,
|
||||
.start_capture = mt9m111_start_capture,
|
||||
.stop_capture = mt9m111_stop_capture,
|
||||
.set_crop = mt9m111_set_crop,
|
||||
.set_fmt = mt9m111_set_fmt,
|
||||
.try_fmt = mt9m111_try_fmt,
|
||||
.query_bus_param = mt9m111_query_bus_param,
|
||||
@ -817,7 +839,7 @@ static int mt9m111_restore_state(struct soc_camera_device *icd)
|
||||
|
||||
mt9m111_set_context(icd, mt9m111->context);
|
||||
mt9m111_set_pixfmt(icd, mt9m111->pixfmt);
|
||||
mt9m111_setup_rect(icd);
|
||||
mt9m111_setup_rect(icd, &mt9m111->rect);
|
||||
mt9m111_set_flip(icd, mt9m111->hflip, MT9M111_RMB_MIRROR_COLS);
|
||||
mt9m111_set_flip(icd, mt9m111->vflip, MT9M111_RMB_MIRROR_ROWS);
|
||||
mt9m111_set_global_gain(icd, icd->gain);
|
||||
|
@ -213,36 +213,14 @@ static void recalculate_limits(struct soc_camera_device *icd,
|
||||
icd->height_max = MT9T031_MAX_HEIGHT / yskip;
|
||||
}
|
||||
|
||||
static int mt9t031_set_fmt(struct soc_camera_device *icd,
|
||||
__u32 pixfmt, struct v4l2_rect *rect)
|
||||
static int mt9t031_set_params(struct soc_camera_device *icd,
|
||||
struct v4l2_rect *rect, u16 xskip, u16 yskip)
|
||||
{
|
||||
struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
|
||||
int ret;
|
||||
u16 xbin, ybin, width, height, left, top;
|
||||
const u16 hblank = MT9T031_HORIZONTAL_BLANK,
|
||||
vblank = MT9T031_VERTICAL_BLANK;
|
||||
u16 xbin, xskip, ybin, yskip, width, height, left, top;
|
||||
|
||||
if (pixfmt) {
|
||||
/*
|
||||
* try_fmt has put rectangle within limits.
|
||||
* S_FMT - use binning and skipping for scaling, recalculate
|
||||
* limits, used for cropping
|
||||
*/
|
||||
/* Is this more optimal than just a division? */
|
||||
for (xskip = 8; xskip > 1; xskip--)
|
||||
if (rect->width * xskip <= MT9T031_MAX_WIDTH)
|
||||
break;
|
||||
|
||||
for (yskip = 8; yskip > 1; yskip--)
|
||||
if (rect->height * yskip <= MT9T031_MAX_HEIGHT)
|
||||
break;
|
||||
|
||||
recalculate_limits(icd, xskip, yskip);
|
||||
} else {
|
||||
/* CROP - no change in scaling, or in limits */
|
||||
xskip = mt9t031->xskip;
|
||||
yskip = mt9t031->yskip;
|
||||
}
|
||||
|
||||
/* Make sure we don't exceed sensor limits */
|
||||
if (rect->left + rect->width > icd->width_max)
|
||||
@ -289,7 +267,7 @@ static int mt9t031_set_fmt(struct soc_camera_device *icd,
|
||||
if (ret >= 0)
|
||||
ret = reg_write(icd, MT9T031_VERTICAL_BLANKING, vblank);
|
||||
|
||||
if (pixfmt) {
|
||||
if (yskip != mt9t031->yskip || xskip != mt9t031->xskip) {
|
||||
/* Binning, skipping */
|
||||
if (ret >= 0)
|
||||
ret = reg_write(icd, MT9T031_COLUMN_ADDRESS_MODE,
|
||||
@ -325,15 +303,58 @@ static int mt9t031_set_fmt(struct soc_camera_device *icd,
|
||||
}
|
||||
}
|
||||
|
||||
if (!ret && pixfmt) {
|
||||
/* Re-enable register update, commit all changes */
|
||||
if (ret >= 0)
|
||||
ret = reg_clear(icd, MT9T031_OUTPUT_CONTROL, 1);
|
||||
|
||||
return ret < 0 ? ret : 0;
|
||||
}
|
||||
|
||||
static int mt9t031_set_crop(struct soc_camera_device *icd,
|
||||
struct v4l2_rect *rect)
|
||||
{
|
||||
struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
|
||||
|
||||
/* CROP - no change in scaling, or in limits */
|
||||
return mt9t031_set_params(icd, rect, mt9t031->xskip, mt9t031->yskip);
|
||||
}
|
||||
|
||||
static int mt9t031_set_fmt(struct soc_camera_device *icd,
|
||||
struct v4l2_format *f)
|
||||
{
|
||||
struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
|
||||
int ret;
|
||||
u16 xskip, yskip;
|
||||
struct v4l2_rect rect = {
|
||||
.left = icd->x_current,
|
||||
.top = icd->y_current,
|
||||
.width = f->fmt.pix.width,
|
||||
.height = f->fmt.pix.height,
|
||||
};
|
||||
|
||||
/*
|
||||
* try_fmt has put rectangle within limits.
|
||||
* S_FMT - use binning and skipping for scaling, recalculate
|
||||
* limits, used for cropping
|
||||
*/
|
||||
/* Is this more optimal than just a division? */
|
||||
for (xskip = 8; xskip > 1; xskip--)
|
||||
if (rect.width * xskip <= MT9T031_MAX_WIDTH)
|
||||
break;
|
||||
|
||||
for (yskip = 8; yskip > 1; yskip--)
|
||||
if (rect.height * yskip <= MT9T031_MAX_HEIGHT)
|
||||
break;
|
||||
|
||||
recalculate_limits(icd, xskip, yskip);
|
||||
|
||||
ret = mt9t031_set_params(icd, &rect, xskip, yskip);
|
||||
if (!ret) {
|
||||
mt9t031->xskip = xskip;
|
||||
mt9t031->yskip = yskip;
|
||||
}
|
||||
|
||||
/* Re-enable register update, commit all changes */
|
||||
reg_clear(icd, MT9T031_OUTPUT_CONTROL, 1);
|
||||
|
||||
return ret < 0 ? ret : 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mt9t031_try_fmt(struct soc_camera_device *icd,
|
||||
@ -470,6 +491,7 @@ static struct soc_camera_ops mt9t031_ops = {
|
||||
.release = mt9t031_release,
|
||||
.start_capture = mt9t031_start_capture,
|
||||
.stop_capture = mt9t031_stop_capture,
|
||||
.set_crop = mt9t031_set_crop,
|
||||
.set_fmt = mt9t031_set_fmt,
|
||||
.try_fmt = mt9t031_try_fmt,
|
||||
.set_bus_param = mt9t031_set_bus_param,
|
||||
|
@ -340,32 +340,11 @@ static unsigned long mt9v022_query_bus_param(struct soc_camera_device *icd)
|
||||
width_flag;
|
||||
}
|
||||
|
||||
static int mt9v022_set_fmt(struct soc_camera_device *icd,
|
||||
__u32 pixfmt, struct v4l2_rect *rect)
|
||||
static int mt9v022_set_crop(struct soc_camera_device *icd,
|
||||
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(), datawidth is from our supported format list */
|
||||
switch (pixfmt) {
|
||||
case V4L2_PIX_FMT_GREY:
|
||||
case V4L2_PIX_FMT_Y16:
|
||||
if (mt9v022->model != V4L2_IDENT_MT9V022IX7ATM)
|
||||
return -EINVAL;
|
||||
break;
|
||||
case V4L2_PIX_FMT_SBGGR8:
|
||||
case V4L2_PIX_FMT_SBGGR16:
|
||||
if (mt9v022->model != V4L2_IDENT_MT9V022IX7ATC)
|
||||
return -EINVAL;
|
||||
break;
|
||||
case 0:
|
||||
/* No format change, only geometry */
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Like in example app. Contradicts the datasheet though */
|
||||
ret = reg_read(icd, MT9V022_AEC_AGC_ENABLE);
|
||||
if (ret >= 0) {
|
||||
@ -403,6 +382,42 @@ static int mt9v022_set_fmt(struct soc_camera_device *icd,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mt9v022_set_fmt(struct soc_camera_device *icd,
|
||||
struct v4l2_format *f)
|
||||
{
|
||||
struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
|
||||
struct v4l2_pix_format *pix = &f->fmt.pix;
|
||||
struct v4l2_rect rect = {
|
||||
.left = icd->x_current,
|
||||
.top = icd->y_current,
|
||||
.width = pix->width,
|
||||
.height = pix->height,
|
||||
};
|
||||
|
||||
/* The caller provides a supported format, as verified per call to
|
||||
* icd->try_fmt(), datawidth is from our supported format list */
|
||||
switch (pix->pixelformat) {
|
||||
case V4L2_PIX_FMT_GREY:
|
||||
case V4L2_PIX_FMT_Y16:
|
||||
if (mt9v022->model != V4L2_IDENT_MT9V022IX7ATM)
|
||||
return -EINVAL;
|
||||
break;
|
||||
case V4L2_PIX_FMT_SBGGR8:
|
||||
case V4L2_PIX_FMT_SBGGR16:
|
||||
if (mt9v022->model != V4L2_IDENT_MT9V022IX7ATC)
|
||||
return -EINVAL;
|
||||
break;
|
||||
case 0:
|
||||
/* No format change, only geometry */
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* No support for scaling on this camera, just crop. */
|
||||
return mt9v022_set_crop(icd, &rect);
|
||||
}
|
||||
|
||||
static int mt9v022_try_fmt(struct soc_camera_device *icd,
|
||||
struct v4l2_format *f)
|
||||
{
|
||||
@ -544,6 +559,7 @@ static struct soc_camera_ops mt9v022_ops = {
|
||||
.release = mt9v022_release,
|
||||
.start_capture = mt9v022_start_capture,
|
||||
.stop_capture = mt9v022_stop_capture,
|
||||
.set_crop = mt9v022_set_crop,
|
||||
.set_fmt = mt9v022_set_fmt,
|
||||
.try_fmt = mt9v022_try_fmt,
|
||||
.set_bus_param = mt9v022_set_bus_param,
|
||||
|
@ -544,16 +544,14 @@ static void mx3_camera_remove_device(struct soc_camera_device *icd)
|
||||
}
|
||||
|
||||
static bool channel_change_requested(struct soc_camera_device *icd,
|
||||
const struct soc_camera_format_xlate *xlate,
|
||||
__u32 pixfmt, struct v4l2_rect *rect)
|
||||
struct v4l2_rect *rect)
|
||||
{
|
||||
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
|
||||
struct mx3_camera_dev *mx3_cam = ici->priv;
|
||||
struct idmac_channel *ichan = mx3_cam->idmac_channel[0];
|
||||
|
||||
/* So far only one configuration is supported */
|
||||
return pixfmt || (ichan && rect->width * rect->height >
|
||||
icd->width * icd->height);
|
||||
/* Do buffers have to be re-allocated or channel re-configured? */
|
||||
return ichan && rect->width * rect->height > icd->width * icd->height;
|
||||
}
|
||||
|
||||
static int test_platform_param(struct mx3_camera_dev *mx3_cam,
|
||||
@ -733,61 +731,10 @@ passthrough:
|
||||
return formats;
|
||||
}
|
||||
|
||||
static int mx3_camera_set_fmt(struct soc_camera_device *icd,
|
||||
__u32 pixfmt, struct v4l2_rect *rect)
|
||||
static void configure_geometry(struct mx3_camera_dev *mx3_cam,
|
||||
struct v4l2_rect *rect)
|
||||
{
|
||||
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
|
||||
struct mx3_camera_dev *mx3_cam = ici->priv;
|
||||
const struct soc_camera_format_xlate *xlate;
|
||||
u32 ctrl, width_field, height_field;
|
||||
int ret;
|
||||
|
||||
xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
|
||||
if (pixfmt && !xlate) {
|
||||
dev_warn(&ici->dev, "Format %x not found\n", pixfmt);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* We now know pixel formats and can decide upon DMA-channel(s)
|
||||
* So far only direct camera-to-memory is supported
|
||||
*/
|
||||
if (channel_change_requested(icd, xlate, pixfmt, rect)) {
|
||||
dma_cap_mask_t mask;
|
||||
struct dma_chan *chan;
|
||||
struct idmac_channel **ichan = &mx3_cam->idmac_channel[0];
|
||||
/* We have to use IDMAC_IC_7 for Bayer / generic data */
|
||||
struct dma_chan_request rq = {.mx3_cam = mx3_cam,
|
||||
.id = IDMAC_IC_7};
|
||||
|
||||
if (*ichan) {
|
||||
struct videobuf_buffer *vb, *_vb;
|
||||
dma_release_channel(&(*ichan)->dma_chan);
|
||||
*ichan = NULL;
|
||||
mx3_cam->active = NULL;
|
||||
list_for_each_entry_safe(vb, _vb, &mx3_cam->capture, queue) {
|
||||
list_del_init(&vb->queue);
|
||||
vb->state = VIDEOBUF_ERROR;
|
||||
wake_up(&vb->done);
|
||||
}
|
||||
}
|
||||
|
||||
dma_cap_zero(mask);
|
||||
dma_cap_set(DMA_SLAVE, mask);
|
||||
dma_cap_set(DMA_PRIVATE, mask);
|
||||
chan = dma_request_channel(mask, chan_filter, &rq);
|
||||
if (!chan)
|
||||
return -EBUSY;
|
||||
|
||||
*ichan = to_idmac_chan(chan);
|
||||
(*ichan)->client = mx3_cam;
|
||||
}
|
||||
|
||||
/*
|
||||
* Might have to perform a complete interface initialisation like in
|
||||
* ipu_csi_init_interface() in mxc_v4l2_s_param(). Also consider
|
||||
* mxc_v4l2_s_fmt()
|
||||
*/
|
||||
|
||||
/* Setup frame size - this cannot be changed on-the-fly... */
|
||||
width_field = rect->width - 1;
|
||||
@ -808,9 +755,98 @@ static int mx3_camera_set_fmt(struct soc_camera_device *icd,
|
||||
* No need to free resources here if we fail, we'll see if we need to
|
||||
* do this next time we are called
|
||||
*/
|
||||
}
|
||||
|
||||
ret = icd->ops->set_fmt(icd, pixfmt ? xlate->cam_fmt->fourcc : 0, rect);
|
||||
if (pixfmt && !ret) {
|
||||
static int acquire_dma_channel(struct mx3_camera_dev *mx3_cam)
|
||||
{
|
||||
dma_cap_mask_t mask;
|
||||
struct dma_chan *chan;
|
||||
struct idmac_channel **ichan = &mx3_cam->idmac_channel[0];
|
||||
/* We have to use IDMAC_IC_7 for Bayer / generic data */
|
||||
struct dma_chan_request rq = {.mx3_cam = mx3_cam,
|
||||
.id = IDMAC_IC_7};
|
||||
|
||||
if (*ichan) {
|
||||
struct videobuf_buffer *vb, *_vb;
|
||||
dma_release_channel(&(*ichan)->dma_chan);
|
||||
*ichan = NULL;
|
||||
mx3_cam->active = NULL;
|
||||
list_for_each_entry_safe(vb, _vb, &mx3_cam->capture, queue) {
|
||||
list_del_init(&vb->queue);
|
||||
vb->state = VIDEOBUF_ERROR;
|
||||
wake_up(&vb->done);
|
||||
}
|
||||
}
|
||||
|
||||
dma_cap_zero(mask);
|
||||
dma_cap_set(DMA_SLAVE, mask);
|
||||
dma_cap_set(DMA_PRIVATE, mask);
|
||||
chan = dma_request_channel(mask, chan_filter, &rq);
|
||||
if (!chan)
|
||||
return -EBUSY;
|
||||
|
||||
*ichan = to_idmac_chan(chan);
|
||||
(*ichan)->client = mx3_cam;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mx3_camera_set_crop(struct soc_camera_device *icd,
|
||||
struct v4l2_rect *rect)
|
||||
{
|
||||
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
|
||||
struct mx3_camera_dev *mx3_cam = ici->priv;
|
||||
|
||||
/*
|
||||
* We now know pixel formats and can decide upon DMA-channel(s)
|
||||
* So far only direct camera-to-memory is supported
|
||||
*/
|
||||
if (channel_change_requested(icd, rect)) {
|
||||
int ret = acquire_dma_channel(mx3_cam);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
configure_geometry(mx3_cam, rect);
|
||||
|
||||
return icd->ops->set_crop(icd, rect);
|
||||
}
|
||||
|
||||
static int mx3_camera_set_fmt(struct soc_camera_device *icd,
|
||||
struct v4l2_format *f)
|
||||
{
|
||||
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
|
||||
struct mx3_camera_dev *mx3_cam = ici->priv;
|
||||
const struct soc_camera_format_xlate *xlate;
|
||||
struct v4l2_pix_format *pix = &f->fmt.pix;
|
||||
struct v4l2_rect rect = {
|
||||
.left = icd->x_current,
|
||||
.top = icd->y_current,
|
||||
.width = pix->width,
|
||||
.height = pix->height,
|
||||
};
|
||||
int ret;
|
||||
|
||||
xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat);
|
||||
if (!xlate) {
|
||||
dev_warn(&ici->dev, "Format %x not found\n", pix->pixelformat);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = acquire_dma_channel(mx3_cam);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Might have to perform a complete interface initialisation like in
|
||||
* ipu_csi_init_interface() in mxc_v4l2_s_param(). Also consider
|
||||
* mxc_v4l2_s_fmt()
|
||||
*/
|
||||
|
||||
configure_geometry(mx3_cam, &rect);
|
||||
|
||||
ret = icd->ops->set_fmt(icd, f);
|
||||
if (!ret) {
|
||||
icd->buswidth = xlate->buswidth;
|
||||
icd->current_fmt = xlate->host_fmt;
|
||||
}
|
||||
@ -1031,6 +1067,7 @@ static struct soc_camera_host_ops mx3_soc_camera_host_ops = {
|
||||
.suspend = mx3_camera_suspend,
|
||||
.resume = mx3_camera_resume,
|
||||
#endif
|
||||
.set_crop = mx3_camera_set_crop,
|
||||
.set_fmt = mx3_camera_set_fmt,
|
||||
.try_fmt = mx3_camera_try_fmt,
|
||||
.get_formats = mx3_camera_get_formats,
|
||||
|
@ -781,11 +781,9 @@ ov772x_select_win(u32 width, u32 height)
|
||||
return win;
|
||||
}
|
||||
|
||||
static int ov772x_set_fmt(struct soc_camera_device *icd,
|
||||
__u32 pixfmt,
|
||||
struct v4l2_rect *rect)
|
||||
static int ov772x_set_params(struct ov772x_priv *priv, u32 width, u32 height,
|
||||
u32 pixfmt)
|
||||
{
|
||||
struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
|
||||
int ret = -EINVAL;
|
||||
u8 val;
|
||||
int i;
|
||||
@ -806,7 +804,7 @@ static int ov772x_set_fmt(struct soc_camera_device *icd,
|
||||
/*
|
||||
* select win
|
||||
*/
|
||||
priv->win = ov772x_select_win(rect->width, rect->height);
|
||||
priv->win = ov772x_select_win(width, height);
|
||||
|
||||
/*
|
||||
* reset hardware
|
||||
@ -870,6 +868,28 @@ ov772x_set_fmt_error:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ov772x_set_crop(struct soc_camera_device *icd,
|
||||
struct v4l2_rect *rect)
|
||||
{
|
||||
struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
|
||||
|
||||
if (!priv->fmt)
|
||||
return -EINVAL;
|
||||
|
||||
return ov772x_set_params(priv, rect->width, rect->height,
|
||||
priv->fmt->fourcc);
|
||||
}
|
||||
|
||||
static int ov772x_set_fmt(struct soc_camera_device *icd,
|
||||
struct v4l2_format *f)
|
||||
{
|
||||
struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
|
||||
struct v4l2_pix_format *pix = &f->fmt.pix;
|
||||
|
||||
return ov772x_set_params(priv, pix->width, pix->height,
|
||||
pix->pixelformat);
|
||||
}
|
||||
|
||||
static int ov772x_try_fmt(struct soc_camera_device *icd,
|
||||
struct v4l2_format *f)
|
||||
{
|
||||
@ -959,6 +979,7 @@ static struct soc_camera_ops ov772x_ops = {
|
||||
.release = ov772x_release,
|
||||
.start_capture = ov772x_start_capture,
|
||||
.stop_capture = ov772x_stop_capture,
|
||||
.set_crop = ov772x_set_crop,
|
||||
.set_fmt = ov772x_set_fmt,
|
||||
.try_fmt = ov772x_try_fmt,
|
||||
.set_bus_param = ov772x_set_bus_param,
|
||||
|
@ -1150,46 +1150,28 @@ static int pxa_camera_get_formats(struct soc_camera_device *icd, int idx,
|
||||
return formats;
|
||||
}
|
||||
|
||||
static int pxa_camera_set_fmt(struct soc_camera_device *icd,
|
||||
__u32 pixfmt, struct v4l2_rect *rect)
|
||||
static int pxa_camera_set_crop(struct soc_camera_device *icd,
|
||||
struct v4l2_rect *rect)
|
||||
{
|
||||
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
|
||||
struct pxa_camera_dev *pcdev = ici->priv;
|
||||
const struct soc_camera_data_format *cam_fmt = NULL;
|
||||
const struct soc_camera_format_xlate *xlate = NULL;
|
||||
struct soc_camera_sense sense = {
|
||||
.master_clock = pcdev->mclk,
|
||||
.pixel_clock_max = pcdev->ciclk / 4,
|
||||
};
|
||||
int ret;
|
||||
|
||||
if (pixfmt) {
|
||||
xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
|
||||
if (!xlate) {
|
||||
dev_warn(&ici->dev, "Format %x not found\n", pixfmt);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
cam_fmt = xlate->cam_fmt;
|
||||
}
|
||||
|
||||
/* If PCLK is used to latch data from the sensor, check sense */
|
||||
if (pcdev->platform_flags & PXA_CAMERA_PCLK_EN)
|
||||
icd->sense = &sense;
|
||||
|
||||
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);
|
||||
}
|
||||
ret = icd->ops->set_crop(icd, rect);
|
||||
|
||||
icd->sense = NULL;
|
||||
|
||||
if (ret < 0) {
|
||||
dev_warn(&ici->dev, "Failed to configure for format %x\n",
|
||||
pixfmt);
|
||||
dev_warn(&ici->dev, "Failed to crop to %ux%u@%u:%u\n",
|
||||
rect->width, rect->height, rect->left, rect->top);
|
||||
} else if (sense.flags & SOCAM_SENSE_PCLK_CHANGED) {
|
||||
if (sense.pixel_clock > sense.pixel_clock_max) {
|
||||
dev_err(&ici->dev,
|
||||
@ -1200,7 +1182,55 @@ static int pxa_camera_set_fmt(struct soc_camera_device *icd,
|
||||
recalculate_fifo_timeout(pcdev, sense.pixel_clock);
|
||||
}
|
||||
|
||||
if (pixfmt && !ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int pxa_camera_set_fmt(struct soc_camera_device *icd,
|
||||
struct v4l2_format *f)
|
||||
{
|
||||
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
|
||||
struct pxa_camera_dev *pcdev = ici->priv;
|
||||
const struct soc_camera_data_format *cam_fmt = NULL;
|
||||
const struct soc_camera_format_xlate *xlate = NULL;
|
||||
struct soc_camera_sense sense = {
|
||||
.master_clock = pcdev->mclk,
|
||||
.pixel_clock_max = pcdev->ciclk / 4,
|
||||
};
|
||||
struct v4l2_pix_format *pix = &f->fmt.pix;
|
||||
struct v4l2_format cam_f = *f;
|
||||
int ret;
|
||||
|
||||
xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat);
|
||||
if (!xlate) {
|
||||
dev_warn(&ici->dev, "Format %x not found\n", pix->pixelformat);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
cam_fmt = xlate->cam_fmt;
|
||||
|
||||
/* If PCLK is used to latch data from the sensor, check sense */
|
||||
if (pcdev->platform_flags & PXA_CAMERA_PCLK_EN)
|
||||
icd->sense = &sense;
|
||||
|
||||
cam_f.fmt.pix.pixelformat = cam_fmt->fourcc;
|
||||
ret = icd->ops->set_fmt(icd, &cam_f);
|
||||
|
||||
icd->sense = NULL;
|
||||
|
||||
if (ret < 0) {
|
||||
dev_warn(&ici->dev, "Failed to configure for format %x\n",
|
||||
pix->pixelformat);
|
||||
} else if (sense.flags & SOCAM_SENSE_PCLK_CHANGED) {
|
||||
if (sense.pixel_clock > sense.pixel_clock_max) {
|
||||
dev_err(&ici->dev,
|
||||
"pixel clock %lu set by the camera too high!",
|
||||
sense.pixel_clock);
|
||||
return -EIO;
|
||||
}
|
||||
recalculate_fifo_timeout(pcdev, sense.pixel_clock);
|
||||
}
|
||||
|
||||
if (!ret) {
|
||||
icd->buswidth = xlate->buswidth;
|
||||
icd->current_fmt = xlate->host_fmt;
|
||||
}
|
||||
@ -1364,6 +1394,7 @@ 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_crop = pxa_camera_set_crop,
|
||||
.get_formats = pxa_camera_get_formats,
|
||||
.set_fmt = pxa_camera_set_fmt,
|
||||
.try_fmt = pxa_camera_try_fmt,
|
||||
|
@ -638,24 +638,30 @@ add_single_format:
|
||||
return formats;
|
||||
}
|
||||
|
||||
static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd,
|
||||
struct v4l2_rect *rect)
|
||||
{
|
||||
return icd->ops->set_crop(icd, rect);
|
||||
}
|
||||
|
||||
static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd,
|
||||
__u32 pixfmt, struct v4l2_rect *rect)
|
||||
struct v4l2_format *f)
|
||||
{
|
||||
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
|
||||
struct sh_mobile_ceu_dev *pcdev = ici->priv;
|
||||
__u32 pixfmt = f->fmt.pix.pixelformat;
|
||||
const struct soc_camera_format_xlate *xlate;
|
||||
struct v4l2_format cam_f = *f;
|
||||
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;
|
||||
}
|
||||
|
||||
ret = icd->ops->set_fmt(icd, xlate->cam_fmt->fourcc, rect);
|
||||
cam_f.fmt.pix.pixelformat = xlate->cam_fmt->fourcc;
|
||||
ret = icd->ops->set_fmt(icd, &cam_f);
|
||||
|
||||
if (!ret) {
|
||||
icd->buswidth = xlate->buswidth;
|
||||
@ -787,6 +793,7 @@ static struct soc_camera_host_ops sh_mobile_ceu_host_ops = {
|
||||
.add = sh_mobile_ceu_add_device,
|
||||
.remove = sh_mobile_ceu_remove_device,
|
||||
.get_formats = sh_mobile_ceu_get_formats,
|
||||
.set_crop = sh_mobile_ceu_set_crop,
|
||||
.set_fmt = sh_mobile_ceu_set_fmt,
|
||||
.try_fmt = sh_mobile_ceu_try_fmt,
|
||||
.reqbufs = sh_mobile_ceu_reqbufs,
|
||||
|
@ -417,9 +417,7 @@ static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv,
|
||||
struct soc_camera_device *icd = icf->icd;
|
||||
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
|
||||
struct v4l2_pix_format *pix = &f->fmt.pix;
|
||||
__u32 pixfmt = pix->pixelformat;
|
||||
int ret;
|
||||
struct v4l2_rect rect;
|
||||
|
||||
WARN_ON(priv != file->private_data);
|
||||
|
||||
@ -435,23 +433,19 @@ static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv,
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
rect.left = icd->x_current;
|
||||
rect.top = icd->y_current;
|
||||
rect.width = pix->width;
|
||||
rect.height = pix->height;
|
||||
ret = ici->ops->set_fmt(icd, pix->pixelformat, &rect);
|
||||
ret = ici->ops->set_fmt(icd, f);
|
||||
if (ret < 0) {
|
||||
goto unlock;
|
||||
} else if (!icd->current_fmt ||
|
||||
icd->current_fmt->fourcc != pixfmt) {
|
||||
icd->current_fmt->fourcc != pix->pixelformat) {
|
||||
dev_err(&ici->dev,
|
||||
"Host driver hasn't set up current format correctly!\n");
|
||||
ret = -EINVAL;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
icd->width = rect.width;
|
||||
icd->height = rect.height;
|
||||
icd->width = f->fmt.pix.width;
|
||||
icd->height = f->fmt.pix.height;
|
||||
icf->vb_vidq.field = pix->field;
|
||||
if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
|
||||
dev_warn(&icd->dev, "Attention! Wrong buf-type %d\n",
|
||||
@ -461,7 +455,7 @@ static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv,
|
||||
icd->width, icd->height);
|
||||
|
||||
/* set physical bus parameters */
|
||||
ret = ici->ops->set_bus_param(icd, pixfmt);
|
||||
ret = ici->ops->set_bus_param(icd, pix->pixelformat);
|
||||
|
||||
unlock:
|
||||
mutex_unlock(&icf->vb_vidq.vb_lock);
|
||||
@ -685,7 +679,7 @@ static int soc_camera_s_crop(struct file *file, void *fh,
|
||||
/* Cropping is allowed during a running capture, guard consistency */
|
||||
mutex_lock(&icf->vb_vidq.vb_lock);
|
||||
|
||||
ret = ici->ops->set_fmt(icd, 0, &a->c);
|
||||
ret = ici->ops->set_crop(icd, &a->c);
|
||||
if (!ret) {
|
||||
icd->width = a->c.width;
|
||||
icd->height = a->c.height;
|
||||
@ -918,6 +912,7 @@ int soc_camera_host_register(struct soc_camera_host *ici)
|
||||
if (!ici || !ici->ops ||
|
||||
!ici->ops->try_fmt ||
|
||||
!ici->ops->set_fmt ||
|
||||
!ici->ops->set_crop ||
|
||||
!ici->ops->set_bus_param ||
|
||||
!ici->ops->querycap ||
|
||||
!ici->ops->init_videobuf ||
|
||||
@ -998,6 +993,7 @@ int soc_camera_device_register(struct soc_camera_device *icd)
|
||||
!icd->ops->release ||
|
||||
!icd->ops->start_capture ||
|
||||
!icd->ops->stop_capture ||
|
||||
!icd->ops->set_crop ||
|
||||
!icd->ops->set_fmt ||
|
||||
!icd->ops->try_fmt ||
|
||||
!icd->ops->query_bus_param ||
|
||||
|
@ -79,8 +79,14 @@ soc_camera_platform_query_bus_param(struct soc_camera_device *icd)
|
||||
return p->bus_param;
|
||||
}
|
||||
|
||||
static int soc_camera_platform_set_crop(struct soc_camera_device *icd,
|
||||
struct v4l2_rect *rect)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int soc_camera_platform_set_fmt(struct soc_camera_device *icd,
|
||||
__u32 pixfmt, struct v4l2_rect *rect)
|
||||
struct v4l2_format *f)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@ -125,6 +131,7 @@ 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_crop = soc_camera_platform_set_crop,
|
||||
.set_fmt = soc_camera_platform_set_fmt,
|
||||
.try_fmt = soc_camera_platform_try_fmt,
|
||||
.set_bus_param = soc_camera_platform_set_bus_param,
|
||||
|
@ -641,25 +641,12 @@ static int tw9910_set_register(struct soc_camera_device *icd,
|
||||
}
|
||||
#endif
|
||||
|
||||
static int tw9910_set_fmt(struct soc_camera_device *icd, __u32 pixfmt,
|
||||
struct v4l2_rect *rect)
|
||||
static int tw9910_set_crop(struct soc_camera_device *icd,
|
||||
struct v4l2_rect *rect)
|
||||
{
|
||||
struct tw9910_priv *priv = container_of(icd, struct tw9910_priv, icd);
|
||||
int ret = -EINVAL;
|
||||
u8 val;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* check color format
|
||||
*/
|
||||
for (i = 0 ; i < ARRAY_SIZE(tw9910_color_fmt) ; i++) {
|
||||
if (pixfmt == tw9910_color_fmt[i].fourcc) {
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ret < 0)
|
||||
goto tw9910_set_fmt_error;
|
||||
|
||||
/*
|
||||
* select suitable norm
|
||||
@ -746,8 +733,33 @@ tw9910_set_fmt_error:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tw9910_set_fmt(struct soc_camera_device *icd,
|
||||
struct v4l2_format *f)
|
||||
{
|
||||
struct v4l2_pix_format *pix = &f->fmt.pix;
|
||||
struct v4l2_rect rect = {
|
||||
.left = icd->x_current,
|
||||
.top = icd->y_current,
|
||||
.width = pix->width,
|
||||
.height = pix->height,
|
||||
};
|
||||
int i;
|
||||
|
||||
/*
|
||||
* check color format
|
||||
*/
|
||||
for (i = 0; i < ARRAY_SIZE(tw9910_color_fmt); i++)
|
||||
if (pix->pixelformat == tw9910_color_fmt[i].fourcc)
|
||||
break;
|
||||
|
||||
if (i == ARRAY_SIZE(tw9910_color_fmt))
|
||||
return -EINVAL;
|
||||
|
||||
return tw9910_set_crop(icd, &rect);
|
||||
}
|
||||
|
||||
static int tw9910_try_fmt(struct soc_camera_device *icd,
|
||||
struct v4l2_format *f)
|
||||
struct v4l2_format *f)
|
||||
{
|
||||
struct v4l2_pix_format *pix = &f->fmt.pix;
|
||||
const struct tw9910_scale_ctrl *scale;
|
||||
@ -835,6 +847,7 @@ static struct soc_camera_ops tw9910_ops = {
|
||||
.release = tw9910_release,
|
||||
.start_capture = tw9910_start_capture,
|
||||
.stop_capture = tw9910_stop_capture,
|
||||
.set_crop = tw9910_set_crop,
|
||||
.set_fmt = tw9910_set_fmt,
|
||||
.try_fmt = tw9910_try_fmt,
|
||||
.set_bus_param = tw9910_set_bus_param,
|
||||
|
@ -74,7 +74,8 @@ struct soc_camera_host_ops {
|
||||
int (*resume)(struct soc_camera_device *);
|
||||
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 (*set_crop)(struct soc_camera_device *, struct v4l2_rect *);
|
||||
int (*set_fmt)(struct soc_camera_device *, struct v4l2_format *);
|
||||
int (*try_fmt)(struct soc_camera_device *, struct v4l2_format *);
|
||||
void (*init_videobuf)(struct videobuf_queue *,
|
||||
struct soc_camera_device *);
|
||||
@ -159,7 +160,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)(struct soc_camera_device *, __u32, struct v4l2_rect *);
|
||||
int (*set_crop)(struct soc_camera_device *, struct v4l2_rect *);
|
||||
int (*set_fmt)(struct soc_camera_device *, struct v4l2_format *);
|
||||
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);
|
||||
|
Loading…
Reference in New Issue
Block a user