return 0;
}
-static int tw686x_s_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *f)
+static int tw686x_set_format(struct tw686x_video_channel *vc,
+ unsigned int pixelformat, unsigned int width,
+ unsigned int height, bool realloc)
{
- struct tw686x_video_channel *vc = video_drvdata(file);
struct tw686x_dev *dev = vc->dev;
- u32 val, width, line_width, height;
- unsigned long bitsperframe;
+ u32 val, dma_width, dma_height, dma_line_width;
int err, pb;
- if (vb2_is_busy(&vc->vidq))
- return -EBUSY;
-
- bitsperframe = vc->width * vc->height * vc->format->depth;
- err = tw686x_try_fmt_vid_cap(file, priv, f);
- if (err)
- return err;
-
- vc->format = format_by_fourcc(f->fmt.pix.pixelformat);
- vc->width = f->fmt.pix.width;
- vc->height = f->fmt.pix.height;
+ vc->format = format_by_fourcc(pixelformat);
+ vc->width = width;
+ vc->height = height;
/* We need new DMA buffers if the framesize has changed */
- if (dev->dma_ops->alloc &&
- bitsperframe != vc->width * vc->height * vc->format->depth) {
+ if (dev->dma_ops->alloc && realloc) {
for (pb = 0; pb < 2; pb++)
dev->dma_ops->free(vc, pb);
reg_write(vc->dev, VDMA_CHANNEL_CONFIG[vc->ch], val);
/* Program the DMA frame size */
- width = (vc->width * 2) & 0x7ff;
- height = vc->height / 2;
- line_width = (vc->width * 2) & 0x7ff;
- val = (height << 22) | (line_width << 11) | width;
+ dma_width = (vc->width * 2) & 0x7ff;
+ dma_height = vc->height / 2;
+ dma_line_width = (vc->width * 2) & 0x7ff;
+ val = (dma_height << 22) | (dma_line_width << 11) | dma_width;
reg_write(vc->dev, VDMA_WHP[vc->ch], val);
return 0;
}
+static int tw686x_s_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct tw686x_video_channel *vc = video_drvdata(file);
+ unsigned long area;
+ bool realloc;
+ int err;
+
+ if (vb2_is_busy(&vc->vidq))
+ return -EBUSY;
+
+ area = vc->width * vc->height;
+ err = tw686x_try_fmt_vid_cap(file, priv, f);
+ if (err)
+ return err;
+
+ realloc = area != (f->fmt.pix.width * f->fmt.pix.height);
+ return tw686x_set_format(vc, f->fmt.pix.pixelformat,
+ f->fmt.pix.width, f->fmt.pix.height,
+ realloc);
+}
+
static int tw686x_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
return 0;
}
-static int tw686x_s_std(struct file *file, void *priv, v4l2_std_id id)
+static int tw686x_set_standard(struct tw686x_video_channel *vc, v4l2_std_id id)
{
- struct tw686x_video_channel *vc = video_drvdata(file);
- struct v4l2_format f;
- u32 val, ret;
-
- if (vc->video_standard == id)
- return 0;
-
- if (vb2_is_busy(&vc->vidq))
- return -EBUSY;
+ u32 val;
if (id & V4L2_STD_NTSC)
val = 0;
val |= (1 << (SYS_MODE_DMA_SHIFT + vc->ch));
reg_write(vc->dev, VIDEO_CONTROL1, val);
+ return 0;
+}
+
+static int tw686x_s_std(struct file *file, void *priv, v4l2_std_id id)
+{
+ struct tw686x_video_channel *vc = video_drvdata(file);
+ struct v4l2_format f;
+ int ret;
+
+ if (vc->video_standard == id)
+ return 0;
+
+ if (vb2_is_busy(&vc->vidq))
+ return -EBUSY;
+
+ ret = tw686x_set_standard(vc, id);
+ if (ret)
+ return ret;
/*
* Adjust format after V4L2_STD_525_60/V4L2_STD_625_50 change,
* calling g_fmt and s_fmt will sanitize the height
* according to the standard.
*/
- ret = tw686x_g_fmt_vid_cap(file, priv, &f);
- if (!ret)
- tw686x_s_fmt_vid_cap(file, priv, &f);
+ tw686x_g_fmt_vid_cap(file, priv, &f);
+ tw686x_s_fmt_vid_cap(file, priv, &f);
/*
* Frame decimation depends on the chosen standard,
return 0;
}
+static void tw686x_set_input(struct tw686x_video_channel *vc, unsigned int i)
+{
+ u32 val;
+
+ vc->input = i;
+
+ val = reg_read(vc->dev, VDMA_CHANNEL_CONFIG[vc->ch]);
+ val &= ~(0x3 << 30);
+ val |= i << 30;
+ reg_write(vc->dev, VDMA_CHANNEL_CONFIG[vc->ch], val);
+}
+
static int tw686x_s_input(struct file *file, void *priv, unsigned int i)
{
struct tw686x_video_channel *vc = video_drvdata(file);
- u32 val;
if (i >= TW686X_INPUTS_PER_CH)
return -EINVAL;
if (vb2_is_busy(&vc->vidq))
return -EBUSY;
- vc->input = i;
-
- val = reg_read(vc->dev, VDMA_CHANNEL_CONFIG[vc->ch]);
- val &= ~(0x3 << 30);
- val |= i << 30;
- reg_write(vc->dev, VDMA_CHANNEL_CONFIG[vc->ch], val);
+ tw686x_set_input(vc, i);
return 0;
}
int tw686x_video_init(struct tw686x_dev *dev)
{
- unsigned int ch, val, pb;
+ unsigned int ch, val;
int err;
if (dev->dma_mode == TW686X_DMA_MODE_MEMCPY)
vc->ch = ch;
/* default settings */
- vc->format = &formats[0];
- vc->video_standard = V4L2_STD_NTSC;
- vc->width = TW686X_VIDEO_WIDTH;
- vc->height = TW686X_VIDEO_HEIGHT(vc->video_standard);
- vc->input = 0;
+ err = tw686x_set_standard(vc, V4L2_STD_NTSC);
+ if (err)
+ goto error;
- reg_write(vc->dev, SDT[ch], 0);
- tw686x_set_framerate(vc, 30);
+ err = tw686x_set_format(vc, formats[0].fourcc,
+ TW686X_VIDEO_WIDTH,
+ TW686X_VIDEO_HEIGHT(vc->video_standard),
+ true);
+ if (err)
+ goto error;
+ tw686x_set_input(vc, 0);
+ tw686x_set_framerate(vc, 30);
reg_write(dev, VDELAY_LO[ch], 0x14);
reg_write(dev, HACTIVE_LO[ch], 0xd0);
reg_write(dev, VIDEO_SIZE[ch], 0);
- if (dev->dma_ops->alloc) {
- for (pb = 0; pb < 2; pb++) {
- err = dev->dma_ops->alloc(vc, pb);
- if (err)
- goto error;
- }
- }
-
vc->vidq.io_modes = VB2_READ | VB2_MMAP | VB2_DMABUF;
vc->vidq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
vc->vidq.drv_priv = vc;