18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2005-2006 Micronas USA Inc.
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#include <linux/module.h>
78c2ecf20Sopenharmony_ci#include <linux/delay.h>
88c2ecf20Sopenharmony_ci#include <linux/sched.h>
98c2ecf20Sopenharmony_ci#include <linux/spinlock.h>
108c2ecf20Sopenharmony_ci#include <linux/slab.h>
118c2ecf20Sopenharmony_ci#include <linux/fs.h>
128c2ecf20Sopenharmony_ci#include <linux/unistd.h>
138c2ecf20Sopenharmony_ci#include <linux/time.h>
148c2ecf20Sopenharmony_ci#include <linux/vmalloc.h>
158c2ecf20Sopenharmony_ci#include <linux/pagemap.h>
168c2ecf20Sopenharmony_ci#include <linux/i2c.h>
178c2ecf20Sopenharmony_ci#include <linux/mutex.h>
188c2ecf20Sopenharmony_ci#include <linux/uaccess.h>
198c2ecf20Sopenharmony_ci#include <linux/videodev2.h>
208c2ecf20Sopenharmony_ci#include <media/v4l2-common.h>
218c2ecf20Sopenharmony_ci#include <media/v4l2-ioctl.h>
228c2ecf20Sopenharmony_ci#include <media/v4l2-subdev.h>
238c2ecf20Sopenharmony_ci#include <media/v4l2-event.h>
248c2ecf20Sopenharmony_ci#include <media/videobuf2-vmalloc.h>
258c2ecf20Sopenharmony_ci#include <media/i2c/saa7115.h>
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci#include "go7007-priv.h"
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci#define call_all(dev, o, f, args...) \
308c2ecf20Sopenharmony_ci	v4l2_device_call_until_err(dev, 0, o, f, ##args)
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_cistatic bool valid_pixelformat(u32 pixelformat)
338c2ecf20Sopenharmony_ci{
348c2ecf20Sopenharmony_ci	switch (pixelformat) {
358c2ecf20Sopenharmony_ci	case V4L2_PIX_FMT_MJPEG:
368c2ecf20Sopenharmony_ci	case V4L2_PIX_FMT_MPEG1:
378c2ecf20Sopenharmony_ci	case V4L2_PIX_FMT_MPEG2:
388c2ecf20Sopenharmony_ci	case V4L2_PIX_FMT_MPEG4:
398c2ecf20Sopenharmony_ci		return true;
408c2ecf20Sopenharmony_ci	default:
418c2ecf20Sopenharmony_ci		return false;
428c2ecf20Sopenharmony_ci	}
438c2ecf20Sopenharmony_ci}
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_cistatic u32 get_frame_type_flag(struct go7007_buffer *vb, int format)
468c2ecf20Sopenharmony_ci{
478c2ecf20Sopenharmony_ci	u8 *ptr = vb2_plane_vaddr(&vb->vb.vb2_buf, 0);
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci	switch (format) {
508c2ecf20Sopenharmony_ci	case V4L2_PIX_FMT_MJPEG:
518c2ecf20Sopenharmony_ci		return V4L2_BUF_FLAG_KEYFRAME;
528c2ecf20Sopenharmony_ci	case V4L2_PIX_FMT_MPEG4:
538c2ecf20Sopenharmony_ci		switch ((ptr[vb->frame_offset + 4] >> 6) & 0x3) {
548c2ecf20Sopenharmony_ci		case 0:
558c2ecf20Sopenharmony_ci			return V4L2_BUF_FLAG_KEYFRAME;
568c2ecf20Sopenharmony_ci		case 1:
578c2ecf20Sopenharmony_ci			return V4L2_BUF_FLAG_PFRAME;
588c2ecf20Sopenharmony_ci		case 2:
598c2ecf20Sopenharmony_ci			return V4L2_BUF_FLAG_BFRAME;
608c2ecf20Sopenharmony_ci		default:
618c2ecf20Sopenharmony_ci			return 0;
628c2ecf20Sopenharmony_ci		}
638c2ecf20Sopenharmony_ci	case V4L2_PIX_FMT_MPEG1:
648c2ecf20Sopenharmony_ci	case V4L2_PIX_FMT_MPEG2:
658c2ecf20Sopenharmony_ci		switch ((ptr[vb->frame_offset + 5] >> 3) & 0x7) {
668c2ecf20Sopenharmony_ci		case 1:
678c2ecf20Sopenharmony_ci			return V4L2_BUF_FLAG_KEYFRAME;
688c2ecf20Sopenharmony_ci		case 2:
698c2ecf20Sopenharmony_ci			return V4L2_BUF_FLAG_PFRAME;
708c2ecf20Sopenharmony_ci		case 3:
718c2ecf20Sopenharmony_ci			return V4L2_BUF_FLAG_BFRAME;
728c2ecf20Sopenharmony_ci		default:
738c2ecf20Sopenharmony_ci			return 0;
748c2ecf20Sopenharmony_ci		}
758c2ecf20Sopenharmony_ci	}
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	return 0;
788c2ecf20Sopenharmony_ci}
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_cistatic void get_resolution(struct go7007 *go, int *width, int *height)
818c2ecf20Sopenharmony_ci{
828c2ecf20Sopenharmony_ci	switch (go->standard) {
838c2ecf20Sopenharmony_ci	case GO7007_STD_NTSC:
848c2ecf20Sopenharmony_ci		*width = 720;
858c2ecf20Sopenharmony_ci		*height = 480;
868c2ecf20Sopenharmony_ci		break;
878c2ecf20Sopenharmony_ci	case GO7007_STD_PAL:
888c2ecf20Sopenharmony_ci		*width = 720;
898c2ecf20Sopenharmony_ci		*height = 576;
908c2ecf20Sopenharmony_ci		break;
918c2ecf20Sopenharmony_ci	case GO7007_STD_OTHER:
928c2ecf20Sopenharmony_ci	default:
938c2ecf20Sopenharmony_ci		*width = go->board_info->sensor_width;
948c2ecf20Sopenharmony_ci		*height = go->board_info->sensor_height;
958c2ecf20Sopenharmony_ci		break;
968c2ecf20Sopenharmony_ci	}
978c2ecf20Sopenharmony_ci}
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_cistatic void set_formatting(struct go7007 *go)
1008c2ecf20Sopenharmony_ci{
1018c2ecf20Sopenharmony_ci	if (go->format == V4L2_PIX_FMT_MJPEG) {
1028c2ecf20Sopenharmony_ci		go->pali = 0;
1038c2ecf20Sopenharmony_ci		go->aspect_ratio = GO7007_RATIO_1_1;
1048c2ecf20Sopenharmony_ci		go->gop_size = 0;
1058c2ecf20Sopenharmony_ci		go->ipb = 0;
1068c2ecf20Sopenharmony_ci		go->closed_gop = 0;
1078c2ecf20Sopenharmony_ci		go->repeat_seqhead = 0;
1088c2ecf20Sopenharmony_ci		go->seq_header_enable = 0;
1098c2ecf20Sopenharmony_ci		go->gop_header_enable = 0;
1108c2ecf20Sopenharmony_ci		go->dvd_mode = 0;
1118c2ecf20Sopenharmony_ci		return;
1128c2ecf20Sopenharmony_ci	}
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci	switch (go->format) {
1158c2ecf20Sopenharmony_ci	case V4L2_PIX_FMT_MPEG1:
1168c2ecf20Sopenharmony_ci		go->pali = 0;
1178c2ecf20Sopenharmony_ci		break;
1188c2ecf20Sopenharmony_ci	default:
1198c2ecf20Sopenharmony_ci	case V4L2_PIX_FMT_MPEG2:
1208c2ecf20Sopenharmony_ci		go->pali = 0x48;
1218c2ecf20Sopenharmony_ci		break;
1228c2ecf20Sopenharmony_ci	case V4L2_PIX_FMT_MPEG4:
1238c2ecf20Sopenharmony_ci		/* For future reference: this is the list of MPEG4
1248c2ecf20Sopenharmony_ci		 * profiles that are available, although they are
1258c2ecf20Sopenharmony_ci		 * untested:
1268c2ecf20Sopenharmony_ci		 *
1278c2ecf20Sopenharmony_ci		 * Profile		pali
1288c2ecf20Sopenharmony_ci		 * --------------	----
1298c2ecf20Sopenharmony_ci		 * PROFILE_S_L0		0x08
1308c2ecf20Sopenharmony_ci		 * PROFILE_S_L1		0x01
1318c2ecf20Sopenharmony_ci		 * PROFILE_S_L2		0x02
1328c2ecf20Sopenharmony_ci		 * PROFILE_S_L3		0x03
1338c2ecf20Sopenharmony_ci		 * PROFILE_ARTS_L1	0x91
1348c2ecf20Sopenharmony_ci		 * PROFILE_ARTS_L2	0x92
1358c2ecf20Sopenharmony_ci		 * PROFILE_ARTS_L3	0x93
1368c2ecf20Sopenharmony_ci		 * PROFILE_ARTS_L4	0x94
1378c2ecf20Sopenharmony_ci		 * PROFILE_AS_L0	0xf0
1388c2ecf20Sopenharmony_ci		 * PROFILE_AS_L1	0xf1
1398c2ecf20Sopenharmony_ci		 * PROFILE_AS_L2	0xf2
1408c2ecf20Sopenharmony_ci		 * PROFILE_AS_L3	0xf3
1418c2ecf20Sopenharmony_ci		 * PROFILE_AS_L4	0xf4
1428c2ecf20Sopenharmony_ci		 * PROFILE_AS_L5	0xf5
1438c2ecf20Sopenharmony_ci		 */
1448c2ecf20Sopenharmony_ci		go->pali = 0xf5;
1458c2ecf20Sopenharmony_ci		break;
1468c2ecf20Sopenharmony_ci	}
1478c2ecf20Sopenharmony_ci	go->gop_size = v4l2_ctrl_g_ctrl(go->mpeg_video_gop_size);
1488c2ecf20Sopenharmony_ci	go->closed_gop = v4l2_ctrl_g_ctrl(go->mpeg_video_gop_closure);
1498c2ecf20Sopenharmony_ci	go->ipb = v4l2_ctrl_g_ctrl(go->mpeg_video_b_frames) != 0;
1508c2ecf20Sopenharmony_ci	go->bitrate = v4l2_ctrl_g_ctrl(go->mpeg_video_bitrate);
1518c2ecf20Sopenharmony_ci	go->repeat_seqhead = v4l2_ctrl_g_ctrl(go->mpeg_video_rep_seqheader);
1528c2ecf20Sopenharmony_ci	go->gop_header_enable = 1;
1538c2ecf20Sopenharmony_ci	go->dvd_mode = 0;
1548c2ecf20Sopenharmony_ci	if (go->format == V4L2_PIX_FMT_MPEG2)
1558c2ecf20Sopenharmony_ci		go->dvd_mode =
1568c2ecf20Sopenharmony_ci			go->bitrate == 9800000 &&
1578c2ecf20Sopenharmony_ci			go->gop_size == 15 &&
1588c2ecf20Sopenharmony_ci			go->ipb == 0 &&
1598c2ecf20Sopenharmony_ci			go->repeat_seqhead == 1 &&
1608c2ecf20Sopenharmony_ci			go->closed_gop;
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci	switch (v4l2_ctrl_g_ctrl(go->mpeg_video_aspect_ratio)) {
1638c2ecf20Sopenharmony_ci	default:
1648c2ecf20Sopenharmony_ci	case V4L2_MPEG_VIDEO_ASPECT_1x1:
1658c2ecf20Sopenharmony_ci		go->aspect_ratio = GO7007_RATIO_1_1;
1668c2ecf20Sopenharmony_ci		break;
1678c2ecf20Sopenharmony_ci	case V4L2_MPEG_VIDEO_ASPECT_4x3:
1688c2ecf20Sopenharmony_ci		go->aspect_ratio = GO7007_RATIO_4_3;
1698c2ecf20Sopenharmony_ci		break;
1708c2ecf20Sopenharmony_ci	case V4L2_MPEG_VIDEO_ASPECT_16x9:
1718c2ecf20Sopenharmony_ci		go->aspect_ratio = GO7007_RATIO_16_9;
1728c2ecf20Sopenharmony_ci		break;
1738c2ecf20Sopenharmony_ci	}
1748c2ecf20Sopenharmony_ci}
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_cistatic int set_capture_size(struct go7007 *go, struct v4l2_format *fmt, int try)
1778c2ecf20Sopenharmony_ci{
1788c2ecf20Sopenharmony_ci	int sensor_height = 0, sensor_width = 0;
1798c2ecf20Sopenharmony_ci	int width, height;
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci	if (fmt != NULL && !valid_pixelformat(fmt->fmt.pix.pixelformat))
1828c2ecf20Sopenharmony_ci		return -EINVAL;
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	get_resolution(go, &sensor_width, &sensor_height);
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	if (fmt == NULL) {
1878c2ecf20Sopenharmony_ci		width = sensor_width;
1888c2ecf20Sopenharmony_ci		height = sensor_height;
1898c2ecf20Sopenharmony_ci	} else if (go->board_info->sensor_flags & GO7007_SENSOR_SCALING) {
1908c2ecf20Sopenharmony_ci		if (fmt->fmt.pix.width > sensor_width)
1918c2ecf20Sopenharmony_ci			width = sensor_width;
1928c2ecf20Sopenharmony_ci		else if (fmt->fmt.pix.width < 144)
1938c2ecf20Sopenharmony_ci			width = 144;
1948c2ecf20Sopenharmony_ci		else
1958c2ecf20Sopenharmony_ci			width = fmt->fmt.pix.width & ~0x0f;
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci		if (fmt->fmt.pix.height > sensor_height)
1988c2ecf20Sopenharmony_ci			height = sensor_height;
1998c2ecf20Sopenharmony_ci		else if (fmt->fmt.pix.height < 96)
2008c2ecf20Sopenharmony_ci			height = 96;
2018c2ecf20Sopenharmony_ci		else
2028c2ecf20Sopenharmony_ci			height = fmt->fmt.pix.height & ~0x0f;
2038c2ecf20Sopenharmony_ci	} else {
2048c2ecf20Sopenharmony_ci		width = fmt->fmt.pix.width;
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci		if (width <= sensor_width / 4) {
2078c2ecf20Sopenharmony_ci			width = sensor_width / 4;
2088c2ecf20Sopenharmony_ci			height = sensor_height / 4;
2098c2ecf20Sopenharmony_ci		} else if (width <= sensor_width / 2) {
2108c2ecf20Sopenharmony_ci			width = sensor_width / 2;
2118c2ecf20Sopenharmony_ci			height = sensor_height / 2;
2128c2ecf20Sopenharmony_ci		} else {
2138c2ecf20Sopenharmony_ci			width = sensor_width;
2148c2ecf20Sopenharmony_ci			height = sensor_height;
2158c2ecf20Sopenharmony_ci		}
2168c2ecf20Sopenharmony_ci		width &= ~0xf;
2178c2ecf20Sopenharmony_ci		height &= ~0xf;
2188c2ecf20Sopenharmony_ci	}
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci	if (fmt != NULL) {
2218c2ecf20Sopenharmony_ci		u32 pixelformat = fmt->fmt.pix.pixelformat;
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci		memset(fmt, 0, sizeof(*fmt));
2248c2ecf20Sopenharmony_ci		fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
2258c2ecf20Sopenharmony_ci		fmt->fmt.pix.width = width;
2268c2ecf20Sopenharmony_ci		fmt->fmt.pix.height = height;
2278c2ecf20Sopenharmony_ci		fmt->fmt.pix.pixelformat = pixelformat;
2288c2ecf20Sopenharmony_ci		fmt->fmt.pix.field = V4L2_FIELD_NONE;
2298c2ecf20Sopenharmony_ci		fmt->fmt.pix.bytesperline = 0;
2308c2ecf20Sopenharmony_ci		fmt->fmt.pix.sizeimage = GO7007_BUF_SIZE;
2318c2ecf20Sopenharmony_ci		fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
2328c2ecf20Sopenharmony_ci	}
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci	if (try)
2358c2ecf20Sopenharmony_ci		return 0;
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci	if (fmt)
2388c2ecf20Sopenharmony_ci		go->format = fmt->fmt.pix.pixelformat;
2398c2ecf20Sopenharmony_ci	go->width = width;
2408c2ecf20Sopenharmony_ci	go->height = height;
2418c2ecf20Sopenharmony_ci	go->encoder_h_offset = go->board_info->sensor_h_offset;
2428c2ecf20Sopenharmony_ci	go->encoder_v_offset = go->board_info->sensor_v_offset;
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci	if (go->board_info->sensor_flags & GO7007_SENSOR_SCALING) {
2458c2ecf20Sopenharmony_ci		struct v4l2_subdev_format format = {
2468c2ecf20Sopenharmony_ci			.which = V4L2_SUBDEV_FORMAT_ACTIVE,
2478c2ecf20Sopenharmony_ci		};
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci		format.format.code = MEDIA_BUS_FMT_FIXED;
2508c2ecf20Sopenharmony_ci		format.format.width = fmt ? fmt->fmt.pix.width : width;
2518c2ecf20Sopenharmony_ci		format.format.height = height;
2528c2ecf20Sopenharmony_ci		go->encoder_h_halve = 0;
2538c2ecf20Sopenharmony_ci		go->encoder_v_halve = 0;
2548c2ecf20Sopenharmony_ci		go->encoder_subsample = 0;
2558c2ecf20Sopenharmony_ci		call_all(&go->v4l2_dev, pad, set_fmt, NULL, &format);
2568c2ecf20Sopenharmony_ci	} else {
2578c2ecf20Sopenharmony_ci		if (width <= sensor_width / 4) {
2588c2ecf20Sopenharmony_ci			go->encoder_h_halve = 1;
2598c2ecf20Sopenharmony_ci			go->encoder_v_halve = 1;
2608c2ecf20Sopenharmony_ci			go->encoder_subsample = 1;
2618c2ecf20Sopenharmony_ci		} else if (width <= sensor_width / 2) {
2628c2ecf20Sopenharmony_ci			go->encoder_h_halve = 1;
2638c2ecf20Sopenharmony_ci			go->encoder_v_halve = 1;
2648c2ecf20Sopenharmony_ci			go->encoder_subsample = 0;
2658c2ecf20Sopenharmony_ci		} else {
2668c2ecf20Sopenharmony_ci			go->encoder_h_halve = 0;
2678c2ecf20Sopenharmony_ci			go->encoder_v_halve = 0;
2688c2ecf20Sopenharmony_ci			go->encoder_subsample = 0;
2698c2ecf20Sopenharmony_ci		}
2708c2ecf20Sopenharmony_ci	}
2718c2ecf20Sopenharmony_ci	return 0;
2728c2ecf20Sopenharmony_ci}
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_cistatic int vidioc_querycap(struct file *file, void  *priv,
2758c2ecf20Sopenharmony_ci					struct v4l2_capability *cap)
2768c2ecf20Sopenharmony_ci{
2778c2ecf20Sopenharmony_ci	struct go7007 *go = video_drvdata(file);
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	strscpy(cap->driver, "go7007", sizeof(cap->driver));
2808c2ecf20Sopenharmony_ci	strscpy(cap->card, go->name, sizeof(cap->card));
2818c2ecf20Sopenharmony_ci	strscpy(cap->bus_info, go->bus_info, sizeof(cap->bus_info));
2828c2ecf20Sopenharmony_ci	return 0;
2838c2ecf20Sopenharmony_ci}
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_cistatic int vidioc_enum_fmt_vid_cap(struct file *file, void  *priv,
2868c2ecf20Sopenharmony_ci					struct v4l2_fmtdesc *fmt)
2878c2ecf20Sopenharmony_ci{
2888c2ecf20Sopenharmony_ci	switch (fmt->index) {
2898c2ecf20Sopenharmony_ci	case 0:
2908c2ecf20Sopenharmony_ci		fmt->pixelformat = V4L2_PIX_FMT_MJPEG;
2918c2ecf20Sopenharmony_ci		break;
2928c2ecf20Sopenharmony_ci	case 1:
2938c2ecf20Sopenharmony_ci		fmt->pixelformat = V4L2_PIX_FMT_MPEG1;
2948c2ecf20Sopenharmony_ci		break;
2958c2ecf20Sopenharmony_ci	case 2:
2968c2ecf20Sopenharmony_ci		fmt->pixelformat = V4L2_PIX_FMT_MPEG2;
2978c2ecf20Sopenharmony_ci		break;
2988c2ecf20Sopenharmony_ci	case 3:
2998c2ecf20Sopenharmony_ci		fmt->pixelformat = V4L2_PIX_FMT_MPEG4;
3008c2ecf20Sopenharmony_ci		break;
3018c2ecf20Sopenharmony_ci	default:
3028c2ecf20Sopenharmony_ci		return -EINVAL;
3038c2ecf20Sopenharmony_ci	}
3048c2ecf20Sopenharmony_ci	return 0;
3058c2ecf20Sopenharmony_ci}
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_cistatic int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
3088c2ecf20Sopenharmony_ci					struct v4l2_format *fmt)
3098c2ecf20Sopenharmony_ci{
3108c2ecf20Sopenharmony_ci	struct go7007 *go = video_drvdata(file);
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
3138c2ecf20Sopenharmony_ci	fmt->fmt.pix.width = go->width;
3148c2ecf20Sopenharmony_ci	fmt->fmt.pix.height = go->height;
3158c2ecf20Sopenharmony_ci	fmt->fmt.pix.pixelformat = go->format;
3168c2ecf20Sopenharmony_ci	fmt->fmt.pix.field = V4L2_FIELD_NONE;
3178c2ecf20Sopenharmony_ci	fmt->fmt.pix.bytesperline = 0;
3188c2ecf20Sopenharmony_ci	fmt->fmt.pix.sizeimage = GO7007_BUF_SIZE;
3198c2ecf20Sopenharmony_ci	fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci	return 0;
3228c2ecf20Sopenharmony_ci}
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_cistatic int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
3258c2ecf20Sopenharmony_ci			struct v4l2_format *fmt)
3268c2ecf20Sopenharmony_ci{
3278c2ecf20Sopenharmony_ci	struct go7007 *go = video_drvdata(file);
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci	return set_capture_size(go, fmt, 1);
3308c2ecf20Sopenharmony_ci}
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_cistatic int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
3338c2ecf20Sopenharmony_ci			struct v4l2_format *fmt)
3348c2ecf20Sopenharmony_ci{
3358c2ecf20Sopenharmony_ci	struct go7007 *go = video_drvdata(file);
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci	if (vb2_is_busy(&go->vidq))
3388c2ecf20Sopenharmony_ci		return -EBUSY;
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci	return set_capture_size(go, fmt, 0);
3418c2ecf20Sopenharmony_ci}
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_cistatic int go7007_queue_setup(struct vb2_queue *q,
3448c2ecf20Sopenharmony_ci		unsigned int *num_buffers, unsigned int *num_planes,
3458c2ecf20Sopenharmony_ci		unsigned int sizes[], struct device *alloc_devs[])
3468c2ecf20Sopenharmony_ci{
3478c2ecf20Sopenharmony_ci	sizes[0] = GO7007_BUF_SIZE;
3488c2ecf20Sopenharmony_ci	*num_planes = 1;
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	if (*num_buffers < 2)
3518c2ecf20Sopenharmony_ci		*num_buffers = 2;
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci	return 0;
3548c2ecf20Sopenharmony_ci}
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_cistatic void go7007_buf_queue(struct vb2_buffer *vb)
3578c2ecf20Sopenharmony_ci{
3588c2ecf20Sopenharmony_ci	struct vb2_queue *vq = vb->vb2_queue;
3598c2ecf20Sopenharmony_ci	struct go7007 *go = vb2_get_drv_priv(vq);
3608c2ecf20Sopenharmony_ci	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
3618c2ecf20Sopenharmony_ci	struct go7007_buffer *go7007_vb =
3628c2ecf20Sopenharmony_ci		container_of(vbuf, struct go7007_buffer, vb);
3638c2ecf20Sopenharmony_ci	unsigned long flags;
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci	spin_lock_irqsave(&go->spinlock, flags);
3668c2ecf20Sopenharmony_ci	list_add_tail(&go7007_vb->list, &go->vidq_active);
3678c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&go->spinlock, flags);
3688c2ecf20Sopenharmony_ci}
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_cistatic int go7007_buf_prepare(struct vb2_buffer *vb)
3718c2ecf20Sopenharmony_ci{
3728c2ecf20Sopenharmony_ci	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
3738c2ecf20Sopenharmony_ci	struct go7007_buffer *go7007_vb =
3748c2ecf20Sopenharmony_ci		container_of(vbuf, struct go7007_buffer, vb);
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_ci	go7007_vb->modet_active = 0;
3778c2ecf20Sopenharmony_ci	go7007_vb->frame_offset = 0;
3788c2ecf20Sopenharmony_ci	vb->planes[0].bytesused = 0;
3798c2ecf20Sopenharmony_ci	return 0;
3808c2ecf20Sopenharmony_ci}
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_cistatic void go7007_buf_finish(struct vb2_buffer *vb)
3838c2ecf20Sopenharmony_ci{
3848c2ecf20Sopenharmony_ci	struct vb2_queue *vq = vb->vb2_queue;
3858c2ecf20Sopenharmony_ci	struct go7007 *go = vb2_get_drv_priv(vq);
3868c2ecf20Sopenharmony_ci	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
3878c2ecf20Sopenharmony_ci	struct go7007_buffer *go7007_vb =
3888c2ecf20Sopenharmony_ci		container_of(vbuf, struct go7007_buffer, vb);
3898c2ecf20Sopenharmony_ci	u32 frame_type_flag = get_frame_type_flag(go7007_vb, go->format);
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci	vbuf->flags &= ~(V4L2_BUF_FLAG_KEYFRAME | V4L2_BUF_FLAG_BFRAME |
3928c2ecf20Sopenharmony_ci			V4L2_BUF_FLAG_PFRAME);
3938c2ecf20Sopenharmony_ci	vbuf->flags |= frame_type_flag;
3948c2ecf20Sopenharmony_ci	vbuf->field = V4L2_FIELD_NONE;
3958c2ecf20Sopenharmony_ci}
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_cistatic int go7007_start_streaming(struct vb2_queue *q, unsigned int count)
3988c2ecf20Sopenharmony_ci{
3998c2ecf20Sopenharmony_ci	struct go7007 *go = vb2_get_drv_priv(q);
4008c2ecf20Sopenharmony_ci	int ret;
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_ci	set_formatting(go);
4038c2ecf20Sopenharmony_ci	mutex_lock(&go->hw_lock);
4048c2ecf20Sopenharmony_ci	go->next_seq = 0;
4058c2ecf20Sopenharmony_ci	go->active_buf = NULL;
4068c2ecf20Sopenharmony_ci	go->modet_event_status = 0;
4078c2ecf20Sopenharmony_ci	q->streaming = 1;
4088c2ecf20Sopenharmony_ci	if (go7007_start_encoder(go) < 0)
4098c2ecf20Sopenharmony_ci		ret = -EIO;
4108c2ecf20Sopenharmony_ci	else
4118c2ecf20Sopenharmony_ci		ret = 0;
4128c2ecf20Sopenharmony_ci	mutex_unlock(&go->hw_lock);
4138c2ecf20Sopenharmony_ci	if (ret) {
4148c2ecf20Sopenharmony_ci		q->streaming = 0;
4158c2ecf20Sopenharmony_ci		return ret;
4168c2ecf20Sopenharmony_ci	}
4178c2ecf20Sopenharmony_ci	call_all(&go->v4l2_dev, video, s_stream, 1);
4188c2ecf20Sopenharmony_ci	v4l2_ctrl_grab(go->mpeg_video_gop_size, true);
4198c2ecf20Sopenharmony_ci	v4l2_ctrl_grab(go->mpeg_video_gop_closure, true);
4208c2ecf20Sopenharmony_ci	v4l2_ctrl_grab(go->mpeg_video_bitrate, true);
4218c2ecf20Sopenharmony_ci	v4l2_ctrl_grab(go->mpeg_video_aspect_ratio, true);
4228c2ecf20Sopenharmony_ci	/* Turn on Capture LED */
4238c2ecf20Sopenharmony_ci	if (go->board_id == GO7007_BOARDID_ADS_USBAV_709)
4248c2ecf20Sopenharmony_ci		go7007_write_addr(go, 0x3c82, 0x0005);
4258c2ecf20Sopenharmony_ci	return ret;
4268c2ecf20Sopenharmony_ci}
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_cistatic void go7007_stop_streaming(struct vb2_queue *q)
4298c2ecf20Sopenharmony_ci{
4308c2ecf20Sopenharmony_ci	struct go7007 *go = vb2_get_drv_priv(q);
4318c2ecf20Sopenharmony_ci	unsigned long flags;
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_ci	q->streaming = 0;
4348c2ecf20Sopenharmony_ci	go7007_stream_stop(go);
4358c2ecf20Sopenharmony_ci	mutex_lock(&go->hw_lock);
4368c2ecf20Sopenharmony_ci	go7007_reset_encoder(go);
4378c2ecf20Sopenharmony_ci	mutex_unlock(&go->hw_lock);
4388c2ecf20Sopenharmony_ci	call_all(&go->v4l2_dev, video, s_stream, 0);
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_ci	spin_lock_irqsave(&go->spinlock, flags);
4418c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&go->vidq_active);
4428c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&go->spinlock, flags);
4438c2ecf20Sopenharmony_ci	v4l2_ctrl_grab(go->mpeg_video_gop_size, false);
4448c2ecf20Sopenharmony_ci	v4l2_ctrl_grab(go->mpeg_video_gop_closure, false);
4458c2ecf20Sopenharmony_ci	v4l2_ctrl_grab(go->mpeg_video_bitrate, false);
4468c2ecf20Sopenharmony_ci	v4l2_ctrl_grab(go->mpeg_video_aspect_ratio, false);
4478c2ecf20Sopenharmony_ci	/* Turn on Capture LED */
4488c2ecf20Sopenharmony_ci	if (go->board_id == GO7007_BOARDID_ADS_USBAV_709)
4498c2ecf20Sopenharmony_ci		go7007_write_addr(go, 0x3c82, 0x000d);
4508c2ecf20Sopenharmony_ci}
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_cistatic const struct vb2_ops go7007_video_qops = {
4538c2ecf20Sopenharmony_ci	.queue_setup    = go7007_queue_setup,
4548c2ecf20Sopenharmony_ci	.buf_queue      = go7007_buf_queue,
4558c2ecf20Sopenharmony_ci	.buf_prepare    = go7007_buf_prepare,
4568c2ecf20Sopenharmony_ci	.buf_finish     = go7007_buf_finish,
4578c2ecf20Sopenharmony_ci	.start_streaming = go7007_start_streaming,
4588c2ecf20Sopenharmony_ci	.stop_streaming = go7007_stop_streaming,
4598c2ecf20Sopenharmony_ci	.wait_prepare   = vb2_ops_wait_prepare,
4608c2ecf20Sopenharmony_ci	.wait_finish    = vb2_ops_wait_finish,
4618c2ecf20Sopenharmony_ci};
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_cistatic int vidioc_g_parm(struct file *filp, void *priv,
4648c2ecf20Sopenharmony_ci		struct v4l2_streamparm *parm)
4658c2ecf20Sopenharmony_ci{
4668c2ecf20Sopenharmony_ci	struct go7007 *go = video_drvdata(filp);
4678c2ecf20Sopenharmony_ci	struct v4l2_fract timeperframe = {
4688c2ecf20Sopenharmony_ci		.numerator = 1001 *  go->fps_scale,
4698c2ecf20Sopenharmony_ci		.denominator = go->sensor_framerate,
4708c2ecf20Sopenharmony_ci	};
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_ci	if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
4738c2ecf20Sopenharmony_ci		return -EINVAL;
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ci	parm->parm.capture.readbuffers = 2;
4768c2ecf20Sopenharmony_ci	parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
4778c2ecf20Sopenharmony_ci	parm->parm.capture.timeperframe = timeperframe;
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ci	return 0;
4808c2ecf20Sopenharmony_ci}
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_cistatic int vidioc_s_parm(struct file *filp, void *priv,
4838c2ecf20Sopenharmony_ci		struct v4l2_streamparm *parm)
4848c2ecf20Sopenharmony_ci{
4858c2ecf20Sopenharmony_ci	struct go7007 *go = video_drvdata(filp);
4868c2ecf20Sopenharmony_ci	unsigned int n, d;
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_ci	if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
4898c2ecf20Sopenharmony_ci		return -EINVAL;
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_ci	n = go->sensor_framerate *
4928c2ecf20Sopenharmony_ci		parm->parm.capture.timeperframe.numerator;
4938c2ecf20Sopenharmony_ci	d = 1001 * parm->parm.capture.timeperframe.denominator;
4948c2ecf20Sopenharmony_ci	if (n != 0 && d != 0 && n > d)
4958c2ecf20Sopenharmony_ci		go->fps_scale = (n + d/2) / d;
4968c2ecf20Sopenharmony_ci	else
4978c2ecf20Sopenharmony_ci		go->fps_scale = 1;
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ci	return vidioc_g_parm(filp, priv, parm);
5008c2ecf20Sopenharmony_ci}
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_ci/* VIDIOC_ENUMSTD on go7007 were used for enumerating the supported fps and
5038c2ecf20Sopenharmony_ci   its resolution, when the device is not connected to TV.
5048c2ecf20Sopenharmony_ci   This is were an API abuse, probably used by the lack of specific IOCTL's to
5058c2ecf20Sopenharmony_ci   enumerate it, by the time the driver was written.
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_ci   However, since kernel 2.6.19, two new ioctls (VIDIOC_ENUM_FRAMEINTERVALS
5088c2ecf20Sopenharmony_ci   and VIDIOC_ENUM_FRAMESIZES) were added for this purpose.
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_ci   The two functions below implement the newer ioctls
5118c2ecf20Sopenharmony_ci*/
5128c2ecf20Sopenharmony_cistatic int vidioc_enum_framesizes(struct file *filp, void *priv,
5138c2ecf20Sopenharmony_ci				  struct v4l2_frmsizeenum *fsize)
5148c2ecf20Sopenharmony_ci{
5158c2ecf20Sopenharmony_ci	struct go7007 *go = video_drvdata(filp);
5168c2ecf20Sopenharmony_ci	int width, height;
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_ci	if (fsize->index > 2)
5198c2ecf20Sopenharmony_ci		return -EINVAL;
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_ci	if (!valid_pixelformat(fsize->pixel_format))
5228c2ecf20Sopenharmony_ci		return -EINVAL;
5238c2ecf20Sopenharmony_ci
5248c2ecf20Sopenharmony_ci	get_resolution(go, &width, &height);
5258c2ecf20Sopenharmony_ci	fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
5268c2ecf20Sopenharmony_ci	fsize->discrete.width = (width >> fsize->index) & ~0xf;
5278c2ecf20Sopenharmony_ci	fsize->discrete.height = (height >> fsize->index) & ~0xf;
5288c2ecf20Sopenharmony_ci	return 0;
5298c2ecf20Sopenharmony_ci}
5308c2ecf20Sopenharmony_ci
5318c2ecf20Sopenharmony_cistatic int vidioc_enum_frameintervals(struct file *filp, void *priv,
5328c2ecf20Sopenharmony_ci				      struct v4l2_frmivalenum *fival)
5338c2ecf20Sopenharmony_ci{
5348c2ecf20Sopenharmony_ci	struct go7007 *go = video_drvdata(filp);
5358c2ecf20Sopenharmony_ci	int width, height;
5368c2ecf20Sopenharmony_ci	int i;
5378c2ecf20Sopenharmony_ci
5388c2ecf20Sopenharmony_ci	if (fival->index > 4)
5398c2ecf20Sopenharmony_ci		return -EINVAL;
5408c2ecf20Sopenharmony_ci
5418c2ecf20Sopenharmony_ci	if (!valid_pixelformat(fival->pixel_format))
5428c2ecf20Sopenharmony_ci		return -EINVAL;
5438c2ecf20Sopenharmony_ci
5448c2ecf20Sopenharmony_ci	if (!(go->board_info->sensor_flags & GO7007_SENSOR_SCALING)) {
5458c2ecf20Sopenharmony_ci		get_resolution(go, &width, &height);
5468c2ecf20Sopenharmony_ci		for (i = 0; i <= 2; i++)
5478c2ecf20Sopenharmony_ci			if (fival->width == ((width >> i) & ~0xf) &&
5488c2ecf20Sopenharmony_ci			    fival->height == ((height >> i) & ~0xf))
5498c2ecf20Sopenharmony_ci				break;
5508c2ecf20Sopenharmony_ci		if (i > 2)
5518c2ecf20Sopenharmony_ci			return -EINVAL;
5528c2ecf20Sopenharmony_ci	}
5538c2ecf20Sopenharmony_ci	fival->type = V4L2_FRMIVAL_TYPE_DISCRETE;
5548c2ecf20Sopenharmony_ci	fival->discrete.numerator = 1001 * (fival->index + 1);
5558c2ecf20Sopenharmony_ci	fival->discrete.denominator = go->sensor_framerate;
5568c2ecf20Sopenharmony_ci	return 0;
5578c2ecf20Sopenharmony_ci}
5588c2ecf20Sopenharmony_ci
5598c2ecf20Sopenharmony_cistatic int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *std)
5608c2ecf20Sopenharmony_ci{
5618c2ecf20Sopenharmony_ci	struct go7007 *go = video_drvdata(file);
5628c2ecf20Sopenharmony_ci
5638c2ecf20Sopenharmony_ci	*std = go->std;
5648c2ecf20Sopenharmony_ci	return 0;
5658c2ecf20Sopenharmony_ci}
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_cistatic int go7007_s_std(struct go7007 *go)
5688c2ecf20Sopenharmony_ci{
5698c2ecf20Sopenharmony_ci	if (go->std & V4L2_STD_625_50) {
5708c2ecf20Sopenharmony_ci		go->standard = GO7007_STD_PAL;
5718c2ecf20Sopenharmony_ci		go->sensor_framerate = 25025;
5728c2ecf20Sopenharmony_ci	} else {
5738c2ecf20Sopenharmony_ci		go->standard = GO7007_STD_NTSC;
5748c2ecf20Sopenharmony_ci		go->sensor_framerate = 30000;
5758c2ecf20Sopenharmony_ci	}
5768c2ecf20Sopenharmony_ci
5778c2ecf20Sopenharmony_ci	call_all(&go->v4l2_dev, video, s_std, go->std);
5788c2ecf20Sopenharmony_ci	set_capture_size(go, NULL, 0);
5798c2ecf20Sopenharmony_ci	return 0;
5808c2ecf20Sopenharmony_ci}
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_cistatic int vidioc_s_std(struct file *file, void *priv, v4l2_std_id std)
5838c2ecf20Sopenharmony_ci{
5848c2ecf20Sopenharmony_ci	struct go7007 *go = video_drvdata(file);
5858c2ecf20Sopenharmony_ci
5868c2ecf20Sopenharmony_ci	if (vb2_is_busy(&go->vidq))
5878c2ecf20Sopenharmony_ci		return -EBUSY;
5888c2ecf20Sopenharmony_ci
5898c2ecf20Sopenharmony_ci	go->std = std;
5908c2ecf20Sopenharmony_ci
5918c2ecf20Sopenharmony_ci	return go7007_s_std(go);
5928c2ecf20Sopenharmony_ci}
5938c2ecf20Sopenharmony_ci
5948c2ecf20Sopenharmony_cistatic int vidioc_querystd(struct file *file, void *priv, v4l2_std_id *std)
5958c2ecf20Sopenharmony_ci{
5968c2ecf20Sopenharmony_ci	struct go7007 *go = video_drvdata(file);
5978c2ecf20Sopenharmony_ci
5988c2ecf20Sopenharmony_ci	return call_all(&go->v4l2_dev, video, querystd, std);
5998c2ecf20Sopenharmony_ci}
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_cistatic int vidioc_enum_input(struct file *file, void *priv,
6028c2ecf20Sopenharmony_ci				struct v4l2_input *inp)
6038c2ecf20Sopenharmony_ci{
6048c2ecf20Sopenharmony_ci	struct go7007 *go = video_drvdata(file);
6058c2ecf20Sopenharmony_ci
6068c2ecf20Sopenharmony_ci	if (inp->index >= go->board_info->num_inputs)
6078c2ecf20Sopenharmony_ci		return -EINVAL;
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_ci	strscpy(inp->name, go->board_info->inputs[inp->index].name,
6108c2ecf20Sopenharmony_ci		sizeof(inp->name));
6118c2ecf20Sopenharmony_ci
6128c2ecf20Sopenharmony_ci	/* If this board has a tuner, it will be the first input */
6138c2ecf20Sopenharmony_ci	if ((go->board_info->flags & GO7007_BOARD_HAS_TUNER) &&
6148c2ecf20Sopenharmony_ci			inp->index == 0)
6158c2ecf20Sopenharmony_ci		inp->type = V4L2_INPUT_TYPE_TUNER;
6168c2ecf20Sopenharmony_ci	else
6178c2ecf20Sopenharmony_ci		inp->type = V4L2_INPUT_TYPE_CAMERA;
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_ci	if (go->board_info->num_aud_inputs)
6208c2ecf20Sopenharmony_ci		inp->audioset = (1 << go->board_info->num_aud_inputs) - 1;
6218c2ecf20Sopenharmony_ci	else
6228c2ecf20Sopenharmony_ci		inp->audioset = 0;
6238c2ecf20Sopenharmony_ci	inp->tuner = 0;
6248c2ecf20Sopenharmony_ci	if (go->board_info->sensor_flags & GO7007_SENSOR_TV)
6258c2ecf20Sopenharmony_ci		inp->std = video_devdata(file)->tvnorms;
6268c2ecf20Sopenharmony_ci	else
6278c2ecf20Sopenharmony_ci		inp->std = 0;
6288c2ecf20Sopenharmony_ci
6298c2ecf20Sopenharmony_ci	return 0;
6308c2ecf20Sopenharmony_ci}
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_ci
6338c2ecf20Sopenharmony_cistatic int vidioc_g_input(struct file *file, void *priv, unsigned int *input)
6348c2ecf20Sopenharmony_ci{
6358c2ecf20Sopenharmony_ci	struct go7007 *go = video_drvdata(file);
6368c2ecf20Sopenharmony_ci
6378c2ecf20Sopenharmony_ci	*input = go->input;
6388c2ecf20Sopenharmony_ci
6398c2ecf20Sopenharmony_ci	return 0;
6408c2ecf20Sopenharmony_ci}
6418c2ecf20Sopenharmony_ci
6428c2ecf20Sopenharmony_cistatic int vidioc_enumaudio(struct file *file, void *fh, struct v4l2_audio *a)
6438c2ecf20Sopenharmony_ci{
6448c2ecf20Sopenharmony_ci	struct go7007 *go = video_drvdata(file);
6458c2ecf20Sopenharmony_ci
6468c2ecf20Sopenharmony_ci	if (a->index >= go->board_info->num_aud_inputs)
6478c2ecf20Sopenharmony_ci		return -EINVAL;
6488c2ecf20Sopenharmony_ci	strscpy(a->name, go->board_info->aud_inputs[a->index].name,
6498c2ecf20Sopenharmony_ci		sizeof(a->name));
6508c2ecf20Sopenharmony_ci	a->capability = V4L2_AUDCAP_STEREO;
6518c2ecf20Sopenharmony_ci	return 0;
6528c2ecf20Sopenharmony_ci}
6538c2ecf20Sopenharmony_ci
6548c2ecf20Sopenharmony_cistatic int vidioc_g_audio(struct file *file, void *fh, struct v4l2_audio *a)
6558c2ecf20Sopenharmony_ci{
6568c2ecf20Sopenharmony_ci	struct go7007 *go = video_drvdata(file);
6578c2ecf20Sopenharmony_ci
6588c2ecf20Sopenharmony_ci	a->index = go->aud_input;
6598c2ecf20Sopenharmony_ci	strscpy(a->name, go->board_info->aud_inputs[go->aud_input].name,
6608c2ecf20Sopenharmony_ci		sizeof(a->name));
6618c2ecf20Sopenharmony_ci	a->capability = V4L2_AUDCAP_STEREO;
6628c2ecf20Sopenharmony_ci	return 0;
6638c2ecf20Sopenharmony_ci}
6648c2ecf20Sopenharmony_ci
6658c2ecf20Sopenharmony_cistatic int vidioc_s_audio(struct file *file, void *fh,
6668c2ecf20Sopenharmony_ci	const struct v4l2_audio *a)
6678c2ecf20Sopenharmony_ci{
6688c2ecf20Sopenharmony_ci	struct go7007 *go = video_drvdata(file);
6698c2ecf20Sopenharmony_ci
6708c2ecf20Sopenharmony_ci	if (a->index >= go->board_info->num_aud_inputs)
6718c2ecf20Sopenharmony_ci		return -EINVAL;
6728c2ecf20Sopenharmony_ci	go->aud_input = a->index;
6738c2ecf20Sopenharmony_ci	v4l2_subdev_call(go->sd_audio, audio, s_routing,
6748c2ecf20Sopenharmony_ci		go->board_info->aud_inputs[go->aud_input].audio_input, 0, 0);
6758c2ecf20Sopenharmony_ci	return 0;
6768c2ecf20Sopenharmony_ci}
6778c2ecf20Sopenharmony_ci
6788c2ecf20Sopenharmony_cistatic void go7007_s_input(struct go7007 *go)
6798c2ecf20Sopenharmony_ci{
6808c2ecf20Sopenharmony_ci	unsigned int input = go->input;
6818c2ecf20Sopenharmony_ci
6828c2ecf20Sopenharmony_ci	v4l2_subdev_call(go->sd_video, video, s_routing,
6838c2ecf20Sopenharmony_ci			go->board_info->inputs[input].video_input, 0,
6848c2ecf20Sopenharmony_ci			go->board_info->video_config);
6858c2ecf20Sopenharmony_ci	if (go->board_info->num_aud_inputs) {
6868c2ecf20Sopenharmony_ci		int aud_input = go->board_info->inputs[input].audio_index;
6878c2ecf20Sopenharmony_ci
6888c2ecf20Sopenharmony_ci		v4l2_subdev_call(go->sd_audio, audio, s_routing,
6898c2ecf20Sopenharmony_ci			go->board_info->aud_inputs[aud_input].audio_input, 0, 0);
6908c2ecf20Sopenharmony_ci		go->aud_input = aud_input;
6918c2ecf20Sopenharmony_ci	}
6928c2ecf20Sopenharmony_ci}
6938c2ecf20Sopenharmony_ci
6948c2ecf20Sopenharmony_cistatic int vidioc_s_input(struct file *file, void *priv, unsigned int input)
6958c2ecf20Sopenharmony_ci{
6968c2ecf20Sopenharmony_ci	struct go7007 *go = video_drvdata(file);
6978c2ecf20Sopenharmony_ci
6988c2ecf20Sopenharmony_ci	if (input >= go->board_info->num_inputs)
6998c2ecf20Sopenharmony_ci		return -EINVAL;
7008c2ecf20Sopenharmony_ci	if (vb2_is_busy(&go->vidq))
7018c2ecf20Sopenharmony_ci		return -EBUSY;
7028c2ecf20Sopenharmony_ci
7038c2ecf20Sopenharmony_ci	go->input = input;
7048c2ecf20Sopenharmony_ci	go7007_s_input(go);
7058c2ecf20Sopenharmony_ci
7068c2ecf20Sopenharmony_ci	return 0;
7078c2ecf20Sopenharmony_ci}
7088c2ecf20Sopenharmony_ci
7098c2ecf20Sopenharmony_cistatic int vidioc_g_tuner(struct file *file, void *priv,
7108c2ecf20Sopenharmony_ci				struct v4l2_tuner *t)
7118c2ecf20Sopenharmony_ci{
7128c2ecf20Sopenharmony_ci	struct go7007 *go = video_drvdata(file);
7138c2ecf20Sopenharmony_ci
7148c2ecf20Sopenharmony_ci	if (t->index != 0)
7158c2ecf20Sopenharmony_ci		return -EINVAL;
7168c2ecf20Sopenharmony_ci
7178c2ecf20Sopenharmony_ci	strscpy(t->name, "Tuner", sizeof(t->name));
7188c2ecf20Sopenharmony_ci	return call_all(&go->v4l2_dev, tuner, g_tuner, t);
7198c2ecf20Sopenharmony_ci}
7208c2ecf20Sopenharmony_ci
7218c2ecf20Sopenharmony_cistatic int vidioc_s_tuner(struct file *file, void *priv,
7228c2ecf20Sopenharmony_ci				const struct v4l2_tuner *t)
7238c2ecf20Sopenharmony_ci{
7248c2ecf20Sopenharmony_ci	struct go7007 *go = video_drvdata(file);
7258c2ecf20Sopenharmony_ci
7268c2ecf20Sopenharmony_ci	if (t->index != 0)
7278c2ecf20Sopenharmony_ci		return -EINVAL;
7288c2ecf20Sopenharmony_ci
7298c2ecf20Sopenharmony_ci	return call_all(&go->v4l2_dev, tuner, s_tuner, t);
7308c2ecf20Sopenharmony_ci}
7318c2ecf20Sopenharmony_ci
7328c2ecf20Sopenharmony_cistatic int vidioc_g_frequency(struct file *file, void *priv,
7338c2ecf20Sopenharmony_ci				struct v4l2_frequency *f)
7348c2ecf20Sopenharmony_ci{
7358c2ecf20Sopenharmony_ci	struct go7007 *go = video_drvdata(file);
7368c2ecf20Sopenharmony_ci
7378c2ecf20Sopenharmony_ci	if (f->tuner)
7388c2ecf20Sopenharmony_ci		return -EINVAL;
7398c2ecf20Sopenharmony_ci
7408c2ecf20Sopenharmony_ci	return call_all(&go->v4l2_dev, tuner, g_frequency, f);
7418c2ecf20Sopenharmony_ci}
7428c2ecf20Sopenharmony_ci
7438c2ecf20Sopenharmony_cistatic int vidioc_s_frequency(struct file *file, void *priv,
7448c2ecf20Sopenharmony_ci				const struct v4l2_frequency *f)
7458c2ecf20Sopenharmony_ci{
7468c2ecf20Sopenharmony_ci	struct go7007 *go = video_drvdata(file);
7478c2ecf20Sopenharmony_ci
7488c2ecf20Sopenharmony_ci	if (f->tuner)
7498c2ecf20Sopenharmony_ci		return -EINVAL;
7508c2ecf20Sopenharmony_ci
7518c2ecf20Sopenharmony_ci	return call_all(&go->v4l2_dev, tuner, s_frequency, f);
7528c2ecf20Sopenharmony_ci}
7538c2ecf20Sopenharmony_ci
7548c2ecf20Sopenharmony_cistatic int vidioc_log_status(struct file *file, void *priv)
7558c2ecf20Sopenharmony_ci{
7568c2ecf20Sopenharmony_ci	struct go7007 *go = video_drvdata(file);
7578c2ecf20Sopenharmony_ci
7588c2ecf20Sopenharmony_ci	v4l2_ctrl_log_status(file, priv);
7598c2ecf20Sopenharmony_ci	return call_all(&go->v4l2_dev, core, log_status);
7608c2ecf20Sopenharmony_ci}
7618c2ecf20Sopenharmony_ci
7628c2ecf20Sopenharmony_cistatic int vidioc_subscribe_event(struct v4l2_fh *fh,
7638c2ecf20Sopenharmony_ci				const struct v4l2_event_subscription *sub)
7648c2ecf20Sopenharmony_ci{
7658c2ecf20Sopenharmony_ci
7668c2ecf20Sopenharmony_ci	switch (sub->type) {
7678c2ecf20Sopenharmony_ci	case V4L2_EVENT_MOTION_DET:
7688c2ecf20Sopenharmony_ci		/* Allow for up to 30 events (1 second for NTSC) to be
7698c2ecf20Sopenharmony_ci		 * stored. */
7708c2ecf20Sopenharmony_ci		return v4l2_event_subscribe(fh, sub, 30, NULL);
7718c2ecf20Sopenharmony_ci	default:
7728c2ecf20Sopenharmony_ci		return v4l2_ctrl_subscribe_event(fh, sub);
7738c2ecf20Sopenharmony_ci	}
7748c2ecf20Sopenharmony_ci}
7758c2ecf20Sopenharmony_ci
7768c2ecf20Sopenharmony_ci
7778c2ecf20Sopenharmony_cistatic int go7007_s_ctrl(struct v4l2_ctrl *ctrl)
7788c2ecf20Sopenharmony_ci{
7798c2ecf20Sopenharmony_ci	struct go7007 *go =
7808c2ecf20Sopenharmony_ci		container_of(ctrl->handler, struct go7007, hdl);
7818c2ecf20Sopenharmony_ci	unsigned y;
7828c2ecf20Sopenharmony_ci	u8 *mt;
7838c2ecf20Sopenharmony_ci
7848c2ecf20Sopenharmony_ci	switch (ctrl->id) {
7858c2ecf20Sopenharmony_ci	case V4L2_CID_PIXEL_THRESHOLD0:
7868c2ecf20Sopenharmony_ci		go->modet[0].pixel_threshold = ctrl->val;
7878c2ecf20Sopenharmony_ci		break;
7888c2ecf20Sopenharmony_ci	case V4L2_CID_MOTION_THRESHOLD0:
7898c2ecf20Sopenharmony_ci		go->modet[0].motion_threshold = ctrl->val;
7908c2ecf20Sopenharmony_ci		break;
7918c2ecf20Sopenharmony_ci	case V4L2_CID_MB_THRESHOLD0:
7928c2ecf20Sopenharmony_ci		go->modet[0].mb_threshold = ctrl->val;
7938c2ecf20Sopenharmony_ci		break;
7948c2ecf20Sopenharmony_ci	case V4L2_CID_PIXEL_THRESHOLD1:
7958c2ecf20Sopenharmony_ci		go->modet[1].pixel_threshold = ctrl->val;
7968c2ecf20Sopenharmony_ci		break;
7978c2ecf20Sopenharmony_ci	case V4L2_CID_MOTION_THRESHOLD1:
7988c2ecf20Sopenharmony_ci		go->modet[1].motion_threshold = ctrl->val;
7998c2ecf20Sopenharmony_ci		break;
8008c2ecf20Sopenharmony_ci	case V4L2_CID_MB_THRESHOLD1:
8018c2ecf20Sopenharmony_ci		go->modet[1].mb_threshold = ctrl->val;
8028c2ecf20Sopenharmony_ci		break;
8038c2ecf20Sopenharmony_ci	case V4L2_CID_PIXEL_THRESHOLD2:
8048c2ecf20Sopenharmony_ci		go->modet[2].pixel_threshold = ctrl->val;
8058c2ecf20Sopenharmony_ci		break;
8068c2ecf20Sopenharmony_ci	case V4L2_CID_MOTION_THRESHOLD2:
8078c2ecf20Sopenharmony_ci		go->modet[2].motion_threshold = ctrl->val;
8088c2ecf20Sopenharmony_ci		break;
8098c2ecf20Sopenharmony_ci	case V4L2_CID_MB_THRESHOLD2:
8108c2ecf20Sopenharmony_ci		go->modet[2].mb_threshold = ctrl->val;
8118c2ecf20Sopenharmony_ci		break;
8128c2ecf20Sopenharmony_ci	case V4L2_CID_PIXEL_THRESHOLD3:
8138c2ecf20Sopenharmony_ci		go->modet[3].pixel_threshold = ctrl->val;
8148c2ecf20Sopenharmony_ci		break;
8158c2ecf20Sopenharmony_ci	case V4L2_CID_MOTION_THRESHOLD3:
8168c2ecf20Sopenharmony_ci		go->modet[3].motion_threshold = ctrl->val;
8178c2ecf20Sopenharmony_ci		break;
8188c2ecf20Sopenharmony_ci	case V4L2_CID_MB_THRESHOLD3:
8198c2ecf20Sopenharmony_ci		go->modet[3].mb_threshold = ctrl->val;
8208c2ecf20Sopenharmony_ci		break;
8218c2ecf20Sopenharmony_ci	case V4L2_CID_DETECT_MD_REGION_GRID:
8228c2ecf20Sopenharmony_ci		mt = go->modet_map;
8238c2ecf20Sopenharmony_ci		for (y = 0; y < go->height / 16; y++, mt += go->width / 16)
8248c2ecf20Sopenharmony_ci			memcpy(mt, ctrl->p_new.p_u8 + y * (720 / 16), go->width / 16);
8258c2ecf20Sopenharmony_ci		break;
8268c2ecf20Sopenharmony_ci	default:
8278c2ecf20Sopenharmony_ci		return -EINVAL;
8288c2ecf20Sopenharmony_ci	}
8298c2ecf20Sopenharmony_ci	return 0;
8308c2ecf20Sopenharmony_ci}
8318c2ecf20Sopenharmony_ci
8328c2ecf20Sopenharmony_cistatic const struct v4l2_file_operations go7007_fops = {
8338c2ecf20Sopenharmony_ci	.owner		= THIS_MODULE,
8348c2ecf20Sopenharmony_ci	.open		= v4l2_fh_open,
8358c2ecf20Sopenharmony_ci	.release	= vb2_fop_release,
8368c2ecf20Sopenharmony_ci	.unlocked_ioctl	= video_ioctl2,
8378c2ecf20Sopenharmony_ci	.read		= vb2_fop_read,
8388c2ecf20Sopenharmony_ci	.mmap		= vb2_fop_mmap,
8398c2ecf20Sopenharmony_ci	.poll		= vb2_fop_poll,
8408c2ecf20Sopenharmony_ci};
8418c2ecf20Sopenharmony_ci
8428c2ecf20Sopenharmony_cistatic const struct v4l2_ioctl_ops video_ioctl_ops = {
8438c2ecf20Sopenharmony_ci	.vidioc_querycap          = vidioc_querycap,
8448c2ecf20Sopenharmony_ci	.vidioc_enum_fmt_vid_cap  = vidioc_enum_fmt_vid_cap,
8458c2ecf20Sopenharmony_ci	.vidioc_g_fmt_vid_cap     = vidioc_g_fmt_vid_cap,
8468c2ecf20Sopenharmony_ci	.vidioc_try_fmt_vid_cap   = vidioc_try_fmt_vid_cap,
8478c2ecf20Sopenharmony_ci	.vidioc_s_fmt_vid_cap     = vidioc_s_fmt_vid_cap,
8488c2ecf20Sopenharmony_ci	.vidioc_reqbufs           = vb2_ioctl_reqbufs,
8498c2ecf20Sopenharmony_ci	.vidioc_querybuf          = vb2_ioctl_querybuf,
8508c2ecf20Sopenharmony_ci	.vidioc_qbuf              = vb2_ioctl_qbuf,
8518c2ecf20Sopenharmony_ci	.vidioc_dqbuf             = vb2_ioctl_dqbuf,
8528c2ecf20Sopenharmony_ci	.vidioc_g_std             = vidioc_g_std,
8538c2ecf20Sopenharmony_ci	.vidioc_s_std             = vidioc_s_std,
8548c2ecf20Sopenharmony_ci	.vidioc_querystd          = vidioc_querystd,
8558c2ecf20Sopenharmony_ci	.vidioc_enum_input        = vidioc_enum_input,
8568c2ecf20Sopenharmony_ci	.vidioc_g_input           = vidioc_g_input,
8578c2ecf20Sopenharmony_ci	.vidioc_s_input           = vidioc_s_input,
8588c2ecf20Sopenharmony_ci	.vidioc_enumaudio         = vidioc_enumaudio,
8598c2ecf20Sopenharmony_ci	.vidioc_g_audio           = vidioc_g_audio,
8608c2ecf20Sopenharmony_ci	.vidioc_s_audio           = vidioc_s_audio,
8618c2ecf20Sopenharmony_ci	.vidioc_streamon          = vb2_ioctl_streamon,
8628c2ecf20Sopenharmony_ci	.vidioc_streamoff         = vb2_ioctl_streamoff,
8638c2ecf20Sopenharmony_ci	.vidioc_g_tuner           = vidioc_g_tuner,
8648c2ecf20Sopenharmony_ci	.vidioc_s_tuner           = vidioc_s_tuner,
8658c2ecf20Sopenharmony_ci	.vidioc_g_frequency       = vidioc_g_frequency,
8668c2ecf20Sopenharmony_ci	.vidioc_s_frequency       = vidioc_s_frequency,
8678c2ecf20Sopenharmony_ci	.vidioc_g_parm            = vidioc_g_parm,
8688c2ecf20Sopenharmony_ci	.vidioc_s_parm            = vidioc_s_parm,
8698c2ecf20Sopenharmony_ci	.vidioc_enum_framesizes   = vidioc_enum_framesizes,
8708c2ecf20Sopenharmony_ci	.vidioc_enum_frameintervals = vidioc_enum_frameintervals,
8718c2ecf20Sopenharmony_ci	.vidioc_log_status        = vidioc_log_status,
8728c2ecf20Sopenharmony_ci	.vidioc_subscribe_event   = vidioc_subscribe_event,
8738c2ecf20Sopenharmony_ci	.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
8748c2ecf20Sopenharmony_ci};
8758c2ecf20Sopenharmony_ci
8768c2ecf20Sopenharmony_cistatic const struct video_device go7007_template = {
8778c2ecf20Sopenharmony_ci	.name		= "go7007",
8788c2ecf20Sopenharmony_ci	.fops		= &go7007_fops,
8798c2ecf20Sopenharmony_ci	.release	= video_device_release_empty,
8808c2ecf20Sopenharmony_ci	.ioctl_ops	= &video_ioctl_ops,
8818c2ecf20Sopenharmony_ci	.tvnorms	= V4L2_STD_ALL,
8828c2ecf20Sopenharmony_ci};
8838c2ecf20Sopenharmony_ci
8848c2ecf20Sopenharmony_cistatic const struct v4l2_ctrl_ops go7007_ctrl_ops = {
8858c2ecf20Sopenharmony_ci	.s_ctrl = go7007_s_ctrl,
8868c2ecf20Sopenharmony_ci};
8878c2ecf20Sopenharmony_ci
8888c2ecf20Sopenharmony_cistatic const struct v4l2_ctrl_config go7007_pixel_threshold0_ctrl = {
8898c2ecf20Sopenharmony_ci	.ops = &go7007_ctrl_ops,
8908c2ecf20Sopenharmony_ci	.id = V4L2_CID_PIXEL_THRESHOLD0,
8918c2ecf20Sopenharmony_ci	.name = "Pixel Threshold Region 0",
8928c2ecf20Sopenharmony_ci	.type = V4L2_CTRL_TYPE_INTEGER,
8938c2ecf20Sopenharmony_ci	.def = 20,
8948c2ecf20Sopenharmony_ci	.max = 32767,
8958c2ecf20Sopenharmony_ci	.step = 1,
8968c2ecf20Sopenharmony_ci};
8978c2ecf20Sopenharmony_ci
8988c2ecf20Sopenharmony_cistatic const struct v4l2_ctrl_config go7007_motion_threshold0_ctrl = {
8998c2ecf20Sopenharmony_ci	.ops = &go7007_ctrl_ops,
9008c2ecf20Sopenharmony_ci	.id = V4L2_CID_MOTION_THRESHOLD0,
9018c2ecf20Sopenharmony_ci	.name = "Motion Threshold Region 0",
9028c2ecf20Sopenharmony_ci	.type = V4L2_CTRL_TYPE_INTEGER,
9038c2ecf20Sopenharmony_ci	.def = 80,
9048c2ecf20Sopenharmony_ci	.max = 32767,
9058c2ecf20Sopenharmony_ci	.step = 1,
9068c2ecf20Sopenharmony_ci};
9078c2ecf20Sopenharmony_ci
9088c2ecf20Sopenharmony_cistatic const struct v4l2_ctrl_config go7007_mb_threshold0_ctrl = {
9098c2ecf20Sopenharmony_ci	.ops = &go7007_ctrl_ops,
9108c2ecf20Sopenharmony_ci	.id = V4L2_CID_MB_THRESHOLD0,
9118c2ecf20Sopenharmony_ci	.name = "MB Threshold Region 0",
9128c2ecf20Sopenharmony_ci	.type = V4L2_CTRL_TYPE_INTEGER,
9138c2ecf20Sopenharmony_ci	.def = 200,
9148c2ecf20Sopenharmony_ci	.max = 32767,
9158c2ecf20Sopenharmony_ci	.step = 1,
9168c2ecf20Sopenharmony_ci};
9178c2ecf20Sopenharmony_ci
9188c2ecf20Sopenharmony_cistatic const struct v4l2_ctrl_config go7007_pixel_threshold1_ctrl = {
9198c2ecf20Sopenharmony_ci	.ops = &go7007_ctrl_ops,
9208c2ecf20Sopenharmony_ci	.id = V4L2_CID_PIXEL_THRESHOLD1,
9218c2ecf20Sopenharmony_ci	.name = "Pixel Threshold Region 1",
9228c2ecf20Sopenharmony_ci	.type = V4L2_CTRL_TYPE_INTEGER,
9238c2ecf20Sopenharmony_ci	.def = 20,
9248c2ecf20Sopenharmony_ci	.max = 32767,
9258c2ecf20Sopenharmony_ci	.step = 1,
9268c2ecf20Sopenharmony_ci};
9278c2ecf20Sopenharmony_ci
9288c2ecf20Sopenharmony_cistatic const struct v4l2_ctrl_config go7007_motion_threshold1_ctrl = {
9298c2ecf20Sopenharmony_ci	.ops = &go7007_ctrl_ops,
9308c2ecf20Sopenharmony_ci	.id = V4L2_CID_MOTION_THRESHOLD1,
9318c2ecf20Sopenharmony_ci	.name = "Motion Threshold Region 1",
9328c2ecf20Sopenharmony_ci	.type = V4L2_CTRL_TYPE_INTEGER,
9338c2ecf20Sopenharmony_ci	.def = 80,
9348c2ecf20Sopenharmony_ci	.max = 32767,
9358c2ecf20Sopenharmony_ci	.step = 1,
9368c2ecf20Sopenharmony_ci};
9378c2ecf20Sopenharmony_ci
9388c2ecf20Sopenharmony_cistatic const struct v4l2_ctrl_config go7007_mb_threshold1_ctrl = {
9398c2ecf20Sopenharmony_ci	.ops = &go7007_ctrl_ops,
9408c2ecf20Sopenharmony_ci	.id = V4L2_CID_MB_THRESHOLD1,
9418c2ecf20Sopenharmony_ci	.name = "MB Threshold Region 1",
9428c2ecf20Sopenharmony_ci	.type = V4L2_CTRL_TYPE_INTEGER,
9438c2ecf20Sopenharmony_ci	.def = 200,
9448c2ecf20Sopenharmony_ci	.max = 32767,
9458c2ecf20Sopenharmony_ci	.step = 1,
9468c2ecf20Sopenharmony_ci};
9478c2ecf20Sopenharmony_ci
9488c2ecf20Sopenharmony_cistatic const struct v4l2_ctrl_config go7007_pixel_threshold2_ctrl = {
9498c2ecf20Sopenharmony_ci	.ops = &go7007_ctrl_ops,
9508c2ecf20Sopenharmony_ci	.id = V4L2_CID_PIXEL_THRESHOLD2,
9518c2ecf20Sopenharmony_ci	.name = "Pixel Threshold Region 2",
9528c2ecf20Sopenharmony_ci	.type = V4L2_CTRL_TYPE_INTEGER,
9538c2ecf20Sopenharmony_ci	.def = 20,
9548c2ecf20Sopenharmony_ci	.max = 32767,
9558c2ecf20Sopenharmony_ci	.step = 1,
9568c2ecf20Sopenharmony_ci};
9578c2ecf20Sopenharmony_ci
9588c2ecf20Sopenharmony_cistatic const struct v4l2_ctrl_config go7007_motion_threshold2_ctrl = {
9598c2ecf20Sopenharmony_ci	.ops = &go7007_ctrl_ops,
9608c2ecf20Sopenharmony_ci	.id = V4L2_CID_MOTION_THRESHOLD2,
9618c2ecf20Sopenharmony_ci	.name = "Motion Threshold Region 2",
9628c2ecf20Sopenharmony_ci	.type = V4L2_CTRL_TYPE_INTEGER,
9638c2ecf20Sopenharmony_ci	.def = 80,
9648c2ecf20Sopenharmony_ci	.max = 32767,
9658c2ecf20Sopenharmony_ci	.step = 1,
9668c2ecf20Sopenharmony_ci};
9678c2ecf20Sopenharmony_ci
9688c2ecf20Sopenharmony_cistatic const struct v4l2_ctrl_config go7007_mb_threshold2_ctrl = {
9698c2ecf20Sopenharmony_ci	.ops = &go7007_ctrl_ops,
9708c2ecf20Sopenharmony_ci	.id = V4L2_CID_MB_THRESHOLD2,
9718c2ecf20Sopenharmony_ci	.name = "MB Threshold Region 2",
9728c2ecf20Sopenharmony_ci	.type = V4L2_CTRL_TYPE_INTEGER,
9738c2ecf20Sopenharmony_ci	.def = 200,
9748c2ecf20Sopenharmony_ci	.max = 32767,
9758c2ecf20Sopenharmony_ci	.step = 1,
9768c2ecf20Sopenharmony_ci};
9778c2ecf20Sopenharmony_ci
9788c2ecf20Sopenharmony_cistatic const struct v4l2_ctrl_config go7007_pixel_threshold3_ctrl = {
9798c2ecf20Sopenharmony_ci	.ops = &go7007_ctrl_ops,
9808c2ecf20Sopenharmony_ci	.id = V4L2_CID_PIXEL_THRESHOLD3,
9818c2ecf20Sopenharmony_ci	.name = "Pixel Threshold Region 3",
9828c2ecf20Sopenharmony_ci	.type = V4L2_CTRL_TYPE_INTEGER,
9838c2ecf20Sopenharmony_ci	.def = 20,
9848c2ecf20Sopenharmony_ci	.max = 32767,
9858c2ecf20Sopenharmony_ci	.step = 1,
9868c2ecf20Sopenharmony_ci};
9878c2ecf20Sopenharmony_ci
9888c2ecf20Sopenharmony_cistatic const struct v4l2_ctrl_config go7007_motion_threshold3_ctrl = {
9898c2ecf20Sopenharmony_ci	.ops = &go7007_ctrl_ops,
9908c2ecf20Sopenharmony_ci	.id = V4L2_CID_MOTION_THRESHOLD3,
9918c2ecf20Sopenharmony_ci	.name = "Motion Threshold Region 3",
9928c2ecf20Sopenharmony_ci	.type = V4L2_CTRL_TYPE_INTEGER,
9938c2ecf20Sopenharmony_ci	.def = 80,
9948c2ecf20Sopenharmony_ci	.max = 32767,
9958c2ecf20Sopenharmony_ci	.step = 1,
9968c2ecf20Sopenharmony_ci};
9978c2ecf20Sopenharmony_ci
9988c2ecf20Sopenharmony_cistatic const struct v4l2_ctrl_config go7007_mb_threshold3_ctrl = {
9998c2ecf20Sopenharmony_ci	.ops = &go7007_ctrl_ops,
10008c2ecf20Sopenharmony_ci	.id = V4L2_CID_MB_THRESHOLD3,
10018c2ecf20Sopenharmony_ci	.name = "MB Threshold Region 3",
10028c2ecf20Sopenharmony_ci	.type = V4L2_CTRL_TYPE_INTEGER,
10038c2ecf20Sopenharmony_ci	.def = 200,
10048c2ecf20Sopenharmony_ci	.max = 32767,
10058c2ecf20Sopenharmony_ci	.step = 1,
10068c2ecf20Sopenharmony_ci};
10078c2ecf20Sopenharmony_ci
10088c2ecf20Sopenharmony_cistatic const struct v4l2_ctrl_config go7007_mb_regions_ctrl = {
10098c2ecf20Sopenharmony_ci	.ops = &go7007_ctrl_ops,
10108c2ecf20Sopenharmony_ci	.id = V4L2_CID_DETECT_MD_REGION_GRID,
10118c2ecf20Sopenharmony_ci	.dims = { 576 / 16, 720 / 16 },
10128c2ecf20Sopenharmony_ci	.max = 3,
10138c2ecf20Sopenharmony_ci	.step = 1,
10148c2ecf20Sopenharmony_ci};
10158c2ecf20Sopenharmony_ci
10168c2ecf20Sopenharmony_ciint go7007_v4l2_ctrl_init(struct go7007 *go)
10178c2ecf20Sopenharmony_ci{
10188c2ecf20Sopenharmony_ci	struct v4l2_ctrl_handler *hdl = &go->hdl;
10198c2ecf20Sopenharmony_ci	struct v4l2_ctrl *ctrl;
10208c2ecf20Sopenharmony_ci
10218c2ecf20Sopenharmony_ci	v4l2_ctrl_handler_init(hdl, 22);
10228c2ecf20Sopenharmony_ci	go->mpeg_video_gop_size = v4l2_ctrl_new_std(hdl, NULL,
10238c2ecf20Sopenharmony_ci			V4L2_CID_MPEG_VIDEO_GOP_SIZE, 0, 34, 1, 15);
10248c2ecf20Sopenharmony_ci	go->mpeg_video_gop_closure = v4l2_ctrl_new_std(hdl, NULL,
10258c2ecf20Sopenharmony_ci			V4L2_CID_MPEG_VIDEO_GOP_CLOSURE, 0, 1, 1, 1);
10268c2ecf20Sopenharmony_ci	go->mpeg_video_bitrate = v4l2_ctrl_new_std(hdl, NULL,
10278c2ecf20Sopenharmony_ci			V4L2_CID_MPEG_VIDEO_BITRATE,
10288c2ecf20Sopenharmony_ci			64000, 10000000, 1, 9800000);
10298c2ecf20Sopenharmony_ci	go->mpeg_video_b_frames = v4l2_ctrl_new_std(hdl, NULL,
10308c2ecf20Sopenharmony_ci			V4L2_CID_MPEG_VIDEO_B_FRAMES, 0, 2, 2, 0);
10318c2ecf20Sopenharmony_ci	go->mpeg_video_rep_seqheader = v4l2_ctrl_new_std(hdl, NULL,
10328c2ecf20Sopenharmony_ci			V4L2_CID_MPEG_VIDEO_REPEAT_SEQ_HEADER, 0, 1, 1, 1);
10338c2ecf20Sopenharmony_ci
10348c2ecf20Sopenharmony_ci	go->mpeg_video_aspect_ratio = v4l2_ctrl_new_std_menu(hdl, NULL,
10358c2ecf20Sopenharmony_ci			V4L2_CID_MPEG_VIDEO_ASPECT,
10368c2ecf20Sopenharmony_ci			V4L2_MPEG_VIDEO_ASPECT_16x9, 0,
10378c2ecf20Sopenharmony_ci			V4L2_MPEG_VIDEO_ASPECT_1x1);
10388c2ecf20Sopenharmony_ci	ctrl = v4l2_ctrl_new_std(hdl, NULL,
10398c2ecf20Sopenharmony_ci			V4L2_CID_JPEG_ACTIVE_MARKER, 0,
10408c2ecf20Sopenharmony_ci			V4L2_JPEG_ACTIVE_MARKER_DQT |
10418c2ecf20Sopenharmony_ci			V4L2_JPEG_ACTIVE_MARKER_DHT, 0,
10428c2ecf20Sopenharmony_ci			V4L2_JPEG_ACTIVE_MARKER_DQT |
10438c2ecf20Sopenharmony_ci			V4L2_JPEG_ACTIVE_MARKER_DHT);
10448c2ecf20Sopenharmony_ci	if (ctrl)
10458c2ecf20Sopenharmony_ci		ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
10468c2ecf20Sopenharmony_ci	v4l2_ctrl_new_custom(hdl, &go7007_pixel_threshold0_ctrl, NULL);
10478c2ecf20Sopenharmony_ci	v4l2_ctrl_new_custom(hdl, &go7007_motion_threshold0_ctrl, NULL);
10488c2ecf20Sopenharmony_ci	v4l2_ctrl_new_custom(hdl, &go7007_mb_threshold0_ctrl, NULL);
10498c2ecf20Sopenharmony_ci	v4l2_ctrl_new_custom(hdl, &go7007_pixel_threshold1_ctrl, NULL);
10508c2ecf20Sopenharmony_ci	v4l2_ctrl_new_custom(hdl, &go7007_motion_threshold1_ctrl, NULL);
10518c2ecf20Sopenharmony_ci	v4l2_ctrl_new_custom(hdl, &go7007_mb_threshold1_ctrl, NULL);
10528c2ecf20Sopenharmony_ci	v4l2_ctrl_new_custom(hdl, &go7007_pixel_threshold2_ctrl, NULL);
10538c2ecf20Sopenharmony_ci	v4l2_ctrl_new_custom(hdl, &go7007_motion_threshold2_ctrl, NULL);
10548c2ecf20Sopenharmony_ci	v4l2_ctrl_new_custom(hdl, &go7007_mb_threshold2_ctrl, NULL);
10558c2ecf20Sopenharmony_ci	v4l2_ctrl_new_custom(hdl, &go7007_pixel_threshold3_ctrl, NULL);
10568c2ecf20Sopenharmony_ci	v4l2_ctrl_new_custom(hdl, &go7007_motion_threshold3_ctrl, NULL);
10578c2ecf20Sopenharmony_ci	v4l2_ctrl_new_custom(hdl, &go7007_mb_threshold3_ctrl, NULL);
10588c2ecf20Sopenharmony_ci	v4l2_ctrl_new_custom(hdl, &go7007_mb_regions_ctrl, NULL);
10598c2ecf20Sopenharmony_ci	go->modet_mode = v4l2_ctrl_new_std_menu(hdl, NULL,
10608c2ecf20Sopenharmony_ci			V4L2_CID_DETECT_MD_MODE,
10618c2ecf20Sopenharmony_ci			V4L2_DETECT_MD_MODE_REGION_GRID,
10628c2ecf20Sopenharmony_ci			1 << V4L2_DETECT_MD_MODE_THRESHOLD_GRID,
10638c2ecf20Sopenharmony_ci			V4L2_DETECT_MD_MODE_DISABLED);
10648c2ecf20Sopenharmony_ci	if (hdl->error) {
10658c2ecf20Sopenharmony_ci		int rv = hdl->error;
10668c2ecf20Sopenharmony_ci
10678c2ecf20Sopenharmony_ci		v4l2_err(&go->v4l2_dev, "Could not register controls\n");
10688c2ecf20Sopenharmony_ci		return rv;
10698c2ecf20Sopenharmony_ci	}
10708c2ecf20Sopenharmony_ci	go->v4l2_dev.ctrl_handler = hdl;
10718c2ecf20Sopenharmony_ci	return 0;
10728c2ecf20Sopenharmony_ci}
10738c2ecf20Sopenharmony_ci
10748c2ecf20Sopenharmony_ciint go7007_v4l2_init(struct go7007 *go)
10758c2ecf20Sopenharmony_ci{
10768c2ecf20Sopenharmony_ci	struct video_device *vdev = &go->vdev;
10778c2ecf20Sopenharmony_ci	int rv;
10788c2ecf20Sopenharmony_ci
10798c2ecf20Sopenharmony_ci	mutex_init(&go->serialize_lock);
10808c2ecf20Sopenharmony_ci	mutex_init(&go->queue_lock);
10818c2ecf20Sopenharmony_ci
10828c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&go->vidq_active);
10838c2ecf20Sopenharmony_ci	go->vidq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
10848c2ecf20Sopenharmony_ci	go->vidq.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ;
10858c2ecf20Sopenharmony_ci	go->vidq.ops = &go7007_video_qops;
10868c2ecf20Sopenharmony_ci	go->vidq.mem_ops = &vb2_vmalloc_memops;
10878c2ecf20Sopenharmony_ci	go->vidq.drv_priv = go;
10888c2ecf20Sopenharmony_ci	go->vidq.buf_struct_size = sizeof(struct go7007_buffer);
10898c2ecf20Sopenharmony_ci	go->vidq.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
10908c2ecf20Sopenharmony_ci	go->vidq.lock = &go->queue_lock;
10918c2ecf20Sopenharmony_ci	rv = vb2_queue_init(&go->vidq);
10928c2ecf20Sopenharmony_ci	if (rv)
10938c2ecf20Sopenharmony_ci		return rv;
10948c2ecf20Sopenharmony_ci	*vdev = go7007_template;
10958c2ecf20Sopenharmony_ci	vdev->lock = &go->serialize_lock;
10968c2ecf20Sopenharmony_ci	vdev->queue = &go->vidq;
10978c2ecf20Sopenharmony_ci	vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
10988c2ecf20Sopenharmony_ci			    V4L2_CAP_STREAMING;
10998c2ecf20Sopenharmony_ci	if (go->board_info->num_aud_inputs)
11008c2ecf20Sopenharmony_ci		vdev->device_caps |= V4L2_CAP_AUDIO;
11018c2ecf20Sopenharmony_ci	if (go->board_info->flags & GO7007_BOARD_HAS_TUNER)
11028c2ecf20Sopenharmony_ci		vdev->device_caps |= V4L2_CAP_TUNER;
11038c2ecf20Sopenharmony_ci	video_set_drvdata(vdev, go);
11048c2ecf20Sopenharmony_ci	vdev->v4l2_dev = &go->v4l2_dev;
11058c2ecf20Sopenharmony_ci	if (!v4l2_device_has_op(&go->v4l2_dev, 0, video, querystd))
11068c2ecf20Sopenharmony_ci		v4l2_disable_ioctl(vdev, VIDIOC_QUERYSTD);
11078c2ecf20Sopenharmony_ci	if (!(go->board_info->flags & GO7007_BOARD_HAS_TUNER)) {
11088c2ecf20Sopenharmony_ci		v4l2_disable_ioctl(vdev, VIDIOC_S_FREQUENCY);
11098c2ecf20Sopenharmony_ci		v4l2_disable_ioctl(vdev, VIDIOC_G_FREQUENCY);
11108c2ecf20Sopenharmony_ci		v4l2_disable_ioctl(vdev, VIDIOC_S_TUNER);
11118c2ecf20Sopenharmony_ci		v4l2_disable_ioctl(vdev, VIDIOC_G_TUNER);
11128c2ecf20Sopenharmony_ci	} else {
11138c2ecf20Sopenharmony_ci		struct v4l2_frequency f = {
11148c2ecf20Sopenharmony_ci			.type = V4L2_TUNER_ANALOG_TV,
11158c2ecf20Sopenharmony_ci			.frequency = 980,
11168c2ecf20Sopenharmony_ci		};
11178c2ecf20Sopenharmony_ci
11188c2ecf20Sopenharmony_ci		call_all(&go->v4l2_dev, tuner, s_frequency, &f);
11198c2ecf20Sopenharmony_ci	}
11208c2ecf20Sopenharmony_ci	if (!(go->board_info->sensor_flags & GO7007_SENSOR_TV)) {
11218c2ecf20Sopenharmony_ci		v4l2_disable_ioctl(vdev, VIDIOC_G_STD);
11228c2ecf20Sopenharmony_ci		v4l2_disable_ioctl(vdev, VIDIOC_S_STD);
11238c2ecf20Sopenharmony_ci		vdev->tvnorms = 0;
11248c2ecf20Sopenharmony_ci	}
11258c2ecf20Sopenharmony_ci	if (go->board_info->sensor_flags & GO7007_SENSOR_SCALING)
11268c2ecf20Sopenharmony_ci		v4l2_disable_ioctl(vdev, VIDIOC_ENUM_FRAMESIZES);
11278c2ecf20Sopenharmony_ci	if (go->board_info->num_aud_inputs == 0) {
11288c2ecf20Sopenharmony_ci		v4l2_disable_ioctl(vdev, VIDIOC_G_AUDIO);
11298c2ecf20Sopenharmony_ci		v4l2_disable_ioctl(vdev, VIDIOC_S_AUDIO);
11308c2ecf20Sopenharmony_ci		v4l2_disable_ioctl(vdev, VIDIOC_ENUMAUDIO);
11318c2ecf20Sopenharmony_ci	}
11328c2ecf20Sopenharmony_ci	/* Setup correct crystal frequency on this board */
11338c2ecf20Sopenharmony_ci	if (go->board_info->sensor_flags & GO7007_SENSOR_SAA7115)
11348c2ecf20Sopenharmony_ci		v4l2_subdev_call(go->sd_video, video, s_crystal_freq,
11358c2ecf20Sopenharmony_ci				SAA7115_FREQ_24_576_MHZ,
11368c2ecf20Sopenharmony_ci				SAA7115_FREQ_FL_APLL | SAA7115_FREQ_FL_UCGC |
11378c2ecf20Sopenharmony_ci				SAA7115_FREQ_FL_DOUBLE_ASCLK);
11388c2ecf20Sopenharmony_ci	go7007_s_input(go);
11398c2ecf20Sopenharmony_ci	if (go->board_info->sensor_flags & GO7007_SENSOR_TV)
11408c2ecf20Sopenharmony_ci		go7007_s_std(go);
11418c2ecf20Sopenharmony_ci	rv = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
11428c2ecf20Sopenharmony_ci	if (rv < 0)
11438c2ecf20Sopenharmony_ci		return rv;
11448c2ecf20Sopenharmony_ci	dev_info(go->dev, "registered device %s [v4l2]\n",
11458c2ecf20Sopenharmony_ci		 video_device_node_name(vdev));
11468c2ecf20Sopenharmony_ci
11478c2ecf20Sopenharmony_ci	return 0;
11488c2ecf20Sopenharmony_ci}
11498c2ecf20Sopenharmony_ci
11508c2ecf20Sopenharmony_civoid go7007_v4l2_remove(struct go7007 *go)
11518c2ecf20Sopenharmony_ci{
11528c2ecf20Sopenharmony_ci	v4l2_ctrl_handler_free(&go->hdl);
11538c2ecf20Sopenharmony_ci}
1154