1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2b285192aSMauro Carvalho Chehab /*
3b285192aSMauro Carvalho Chehab  *
4b285192aSMauro Carvalho Chehab  * device driver for philips saa7134 based TV cards
5b285192aSMauro Carvalho Chehab  * video4linux video interface
6b285192aSMauro Carvalho Chehab  *
7b285192aSMauro Carvalho Chehab  * (c) 2001-03 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
8b285192aSMauro Carvalho Chehab  */
9b285192aSMauro Carvalho Chehab 
109a12ccfcSMauro Carvalho Chehab #include "saa7134.h"
119a12ccfcSMauro Carvalho Chehab #include "saa7134-reg.h"
129a12ccfcSMauro Carvalho Chehab 
13b285192aSMauro Carvalho Chehab #include <linux/init.h>
14b285192aSMauro Carvalho Chehab #include <linux/list.h>
15b285192aSMauro Carvalho Chehab #include <linux/module.h>
16b285192aSMauro Carvalho Chehab #include <linux/kernel.h>
17b285192aSMauro Carvalho Chehab #include <linux/slab.h>
18b285192aSMauro Carvalho Chehab #include <linux/sort.h>
19b285192aSMauro Carvalho Chehab 
20a2004502SHans Verkuil #include <media/v4l2-common.h>
21a2004502SHans Verkuil #include <media/v4l2-event.h>
22b5dcee22SMauro Carvalho Chehab #include <media/i2c/saa6588.h>
23a2004502SHans Verkuil 
24b285192aSMauro Carvalho Chehab /* ------------------------------------------------------------------ */
25b285192aSMauro Carvalho Chehab 
26b285192aSMauro Carvalho Chehab unsigned int video_debug;
27b285192aSMauro Carvalho Chehab static unsigned int gbuffers      = 8;
28b285192aSMauro Carvalho Chehab static unsigned int noninterlaced; /* 0 */
29b285192aSMauro Carvalho Chehab static unsigned int gbufsize      = 720*576*4;
30b285192aSMauro Carvalho Chehab static unsigned int gbufsize_max  = 720*576*4;
31b285192aSMauro Carvalho Chehab static char secam[] = "--";
32b285192aSMauro Carvalho Chehab module_param(video_debug, int, 0644);
33b285192aSMauro Carvalho Chehab MODULE_PARM_DESC(video_debug,"enable debug messages [video]");
34b285192aSMauro Carvalho Chehab module_param(gbuffers, int, 0444);
35b285192aSMauro Carvalho Chehab MODULE_PARM_DESC(gbuffers,"number of capture buffers, range 2-32");
36b285192aSMauro Carvalho Chehab module_param(noninterlaced, int, 0644);
37b285192aSMauro Carvalho Chehab MODULE_PARM_DESC(noninterlaced,"capture non interlaced video");
38b285192aSMauro Carvalho Chehab module_param_string(secam, secam, sizeof(secam), 0644);
39b285192aSMauro Carvalho Chehab MODULE_PARM_DESC(secam, "force SECAM variant, either DK,L or Lc");
40b285192aSMauro Carvalho Chehab 
41b285192aSMauro Carvalho Chehab 
4245f38cb3SMauro Carvalho Chehab #define video_dbg(fmt, arg...) do { \
4345f38cb3SMauro Carvalho Chehab 	if (video_debug & 0x04) \
4445f38cb3SMauro Carvalho Chehab 		printk(KERN_DEBUG pr_fmt("video: " fmt), ## arg); \
4545f38cb3SMauro Carvalho Chehab 	} while (0)
46b285192aSMauro Carvalho Chehab 
47b285192aSMauro Carvalho Chehab /* ------------------------------------------------------------------ */
48b285192aSMauro Carvalho Chehab /* Defines for Video Output Port Register at address 0x191            */
49b285192aSMauro Carvalho Chehab 
50b285192aSMauro Carvalho Chehab /* Bit 0: VIP code T bit polarity */
51b285192aSMauro Carvalho Chehab 
52b285192aSMauro Carvalho Chehab #define VP_T_CODE_P_NON_INVERTED	0x00
53b285192aSMauro Carvalho Chehab #define VP_T_CODE_P_INVERTED		0x01
54b285192aSMauro Carvalho Chehab 
55b285192aSMauro Carvalho Chehab /* ------------------------------------------------------------------ */
56b285192aSMauro Carvalho Chehab /* Defines for Video Output Port Register at address 0x195            */
57b285192aSMauro Carvalho Chehab 
58b285192aSMauro Carvalho Chehab /* Bit 2: Video output clock delay control */
59b285192aSMauro Carvalho Chehab 
60b285192aSMauro Carvalho Chehab #define VP_CLK_CTRL2_NOT_DELAYED	0x00
61b285192aSMauro Carvalho Chehab #define VP_CLK_CTRL2_DELAYED		0x04
62b285192aSMauro Carvalho Chehab 
63b285192aSMauro Carvalho Chehab /* Bit 1: Video output clock invert control */
64b285192aSMauro Carvalho Chehab 
65b285192aSMauro Carvalho Chehab #define VP_CLK_CTRL1_NON_INVERTED	0x00
66b285192aSMauro Carvalho Chehab #define VP_CLK_CTRL1_INVERTED		0x02
67b285192aSMauro Carvalho Chehab 
68b285192aSMauro Carvalho Chehab /* ------------------------------------------------------------------ */
69b285192aSMauro Carvalho Chehab /* Defines for Video Output Port Register at address 0x196            */
70b285192aSMauro Carvalho Chehab 
71b285192aSMauro Carvalho Chehab /* Bits 2 to 0: VSYNC pin video vertical sync type */
72b285192aSMauro Carvalho Chehab 
73b285192aSMauro Carvalho Chehab #define VP_VS_TYPE_MASK			0x07
74b285192aSMauro Carvalho Chehab 
75b285192aSMauro Carvalho Chehab #define VP_VS_TYPE_OFF			0x00
76b285192aSMauro Carvalho Chehab #define VP_VS_TYPE_V123			0x01
77b285192aSMauro Carvalho Chehab #define VP_VS_TYPE_V_ITU		0x02
78b285192aSMauro Carvalho Chehab #define VP_VS_TYPE_VGATE_L		0x03
79b285192aSMauro Carvalho Chehab #define VP_VS_TYPE_RESERVED1		0x04
80b285192aSMauro Carvalho Chehab #define VP_VS_TYPE_RESERVED2		0x05
81b285192aSMauro Carvalho Chehab #define VP_VS_TYPE_F_ITU		0x06
82b285192aSMauro Carvalho Chehab #define VP_VS_TYPE_SC_FID		0x07
83b285192aSMauro Carvalho Chehab 
84b285192aSMauro Carvalho Chehab /* ------------------------------------------------------------------ */
85b285192aSMauro Carvalho Chehab /* data structs for video                                             */
86b285192aSMauro Carvalho Chehab 
87b285192aSMauro Carvalho Chehab static int video_out[][9] = {
88b285192aSMauro Carvalho Chehab 	[CCIR656] = { 0x00, 0xb1, 0x00, 0xa1, 0x00, 0x04, 0x06, 0x00, 0x00 },
89b285192aSMauro Carvalho Chehab };
90b285192aSMauro Carvalho Chehab 
91b285192aSMauro Carvalho Chehab static struct saa7134_format formats[] = {
92b285192aSMauro Carvalho Chehab 	{
93b285192aSMauro Carvalho Chehab 		.fourcc   = V4L2_PIX_FMT_GREY,
94b285192aSMauro Carvalho Chehab 		.depth    = 8,
95b285192aSMauro Carvalho Chehab 		.pm       = 0x06,
96b285192aSMauro Carvalho Chehab 	},{
97b285192aSMauro Carvalho Chehab 		.fourcc   = V4L2_PIX_FMT_RGB555,
98b285192aSMauro Carvalho Chehab 		.depth    = 16,
99b285192aSMauro Carvalho Chehab 		.pm       = 0x13 | 0x80,
100b285192aSMauro Carvalho Chehab 	},{
101b285192aSMauro Carvalho Chehab 		.fourcc   = V4L2_PIX_FMT_RGB555X,
102b285192aSMauro Carvalho Chehab 		.depth    = 16,
103b285192aSMauro Carvalho Chehab 		.pm       = 0x13 | 0x80,
104b285192aSMauro Carvalho Chehab 		.bswap    = 1,
105b285192aSMauro Carvalho Chehab 	},{
106b285192aSMauro Carvalho Chehab 		.fourcc   = V4L2_PIX_FMT_RGB565,
107b285192aSMauro Carvalho Chehab 		.depth    = 16,
108b285192aSMauro Carvalho Chehab 		.pm       = 0x10 | 0x80,
109b285192aSMauro Carvalho Chehab 	},{
110b285192aSMauro Carvalho Chehab 		.fourcc   = V4L2_PIX_FMT_RGB565X,
111b285192aSMauro Carvalho Chehab 		.depth    = 16,
112b285192aSMauro Carvalho Chehab 		.pm       = 0x10 | 0x80,
113b285192aSMauro Carvalho Chehab 		.bswap    = 1,
114b285192aSMauro Carvalho Chehab 	},{
115b285192aSMauro Carvalho Chehab 		.fourcc   = V4L2_PIX_FMT_BGR24,
116b285192aSMauro Carvalho Chehab 		.depth    = 24,
117b285192aSMauro Carvalho Chehab 		.pm       = 0x11,
118b285192aSMauro Carvalho Chehab 	},{
119b285192aSMauro Carvalho Chehab 		.fourcc   = V4L2_PIX_FMT_RGB24,
120b285192aSMauro Carvalho Chehab 		.depth    = 24,
121b285192aSMauro Carvalho Chehab 		.pm       = 0x11,
122b285192aSMauro Carvalho Chehab 		.bswap    = 1,
123b285192aSMauro Carvalho Chehab 	},{
124b285192aSMauro Carvalho Chehab 		.fourcc   = V4L2_PIX_FMT_BGR32,
125b285192aSMauro Carvalho Chehab 		.depth    = 32,
126b285192aSMauro Carvalho Chehab 		.pm       = 0x12,
127b285192aSMauro Carvalho Chehab 	},{
128b285192aSMauro Carvalho Chehab 		.fourcc   = V4L2_PIX_FMT_RGB32,
129b285192aSMauro Carvalho Chehab 		.depth    = 32,
130b285192aSMauro Carvalho Chehab 		.pm       = 0x12,
131b285192aSMauro Carvalho Chehab 		.bswap    = 1,
132b285192aSMauro Carvalho Chehab 		.wswap    = 1,
133b285192aSMauro Carvalho Chehab 	},{
134b285192aSMauro Carvalho Chehab 		.fourcc   = V4L2_PIX_FMT_YUYV,
135b285192aSMauro Carvalho Chehab 		.depth    = 16,
136b285192aSMauro Carvalho Chehab 		.pm       = 0x00,
137b285192aSMauro Carvalho Chehab 		.bswap    = 1,
138b285192aSMauro Carvalho Chehab 		.yuv      = 1,
139b285192aSMauro Carvalho Chehab 	},{
140b285192aSMauro Carvalho Chehab 		.fourcc   = V4L2_PIX_FMT_UYVY,
141b285192aSMauro Carvalho Chehab 		.depth    = 16,
142b285192aSMauro Carvalho Chehab 		.pm       = 0x00,
143b285192aSMauro Carvalho Chehab 		.yuv      = 1,
144b285192aSMauro Carvalho Chehab 	},{
145b285192aSMauro Carvalho Chehab 		.fourcc   = V4L2_PIX_FMT_YUV422P,
146b285192aSMauro Carvalho Chehab 		.depth    = 16,
147b285192aSMauro Carvalho Chehab 		.pm       = 0x09,
148b285192aSMauro Carvalho Chehab 		.yuv      = 1,
149b285192aSMauro Carvalho Chehab 		.planar   = 1,
150b285192aSMauro Carvalho Chehab 		.hshift   = 1,
151b285192aSMauro Carvalho Chehab 		.vshift   = 0,
152b285192aSMauro Carvalho Chehab 	},{
153b285192aSMauro Carvalho Chehab 		.fourcc   = V4L2_PIX_FMT_YUV420,
154b285192aSMauro Carvalho Chehab 		.depth    = 12,
155b285192aSMauro Carvalho Chehab 		.pm       = 0x0a,
156b285192aSMauro Carvalho Chehab 		.yuv      = 1,
157b285192aSMauro Carvalho Chehab 		.planar   = 1,
158b285192aSMauro Carvalho Chehab 		.hshift   = 1,
159b285192aSMauro Carvalho Chehab 		.vshift   = 1,
160b285192aSMauro Carvalho Chehab 	},{
161b285192aSMauro Carvalho Chehab 		.fourcc   = V4L2_PIX_FMT_YVU420,
162b285192aSMauro Carvalho Chehab 		.depth    = 12,
163b285192aSMauro Carvalho Chehab 		.pm       = 0x0a,
164b285192aSMauro Carvalho Chehab 		.yuv      = 1,
165b285192aSMauro Carvalho Chehab 		.planar   = 1,
166b285192aSMauro Carvalho Chehab 		.uvswap   = 1,
167b285192aSMauro Carvalho Chehab 		.hshift   = 1,
168b285192aSMauro Carvalho Chehab 		.vshift   = 1,
169b285192aSMauro Carvalho Chehab 	}
170b285192aSMauro Carvalho Chehab };
171b285192aSMauro Carvalho Chehab #define FORMATS ARRAY_SIZE(formats)
172b285192aSMauro Carvalho Chehab 
173b285192aSMauro Carvalho Chehab #define NORM_625_50			\
174b285192aSMauro Carvalho Chehab 		.h_start       = 0,	\
175b285192aSMauro Carvalho Chehab 		.h_stop        = 719,	\
176b285192aSMauro Carvalho Chehab 		.video_v_start = 24,	\
177b285192aSMauro Carvalho Chehab 		.video_v_stop  = 311,	\
178b285192aSMauro Carvalho Chehab 		.vbi_v_start_0 = 7,	\
179033d0088SHans Verkuil 		.vbi_v_stop_0  = 23,	\
180b285192aSMauro Carvalho Chehab 		.vbi_v_start_1 = 319,   \
181b285192aSMauro Carvalho Chehab 		.src_timing    = 4
182b285192aSMauro Carvalho Chehab 
183b285192aSMauro Carvalho Chehab #define NORM_525_60			\
184b285192aSMauro Carvalho Chehab 		.h_start       = 0,	\
185b285192aSMauro Carvalho Chehab 		.h_stop        = 719,	\
186b285192aSMauro Carvalho Chehab 		.video_v_start = 23,	\
187b285192aSMauro Carvalho Chehab 		.video_v_stop  = 262,	\
188b285192aSMauro Carvalho Chehab 		.vbi_v_start_0 = 10,	\
189b285192aSMauro Carvalho Chehab 		.vbi_v_stop_0  = 21,	\
190b285192aSMauro Carvalho Chehab 		.vbi_v_start_1 = 273,	\
191b285192aSMauro Carvalho Chehab 		.src_timing    = 7
192b285192aSMauro Carvalho Chehab 
193b285192aSMauro Carvalho Chehab static struct saa7134_tvnorm tvnorms[] = {
194b285192aSMauro Carvalho Chehab 	{
195b285192aSMauro Carvalho Chehab 		.name          = "PAL", /* autodetect */
196b285192aSMauro Carvalho Chehab 		.id            = V4L2_STD_PAL,
197b285192aSMauro Carvalho Chehab 		NORM_625_50,
198b285192aSMauro Carvalho Chehab 
199b285192aSMauro Carvalho Chehab 		.sync_control  = 0x18,
200b285192aSMauro Carvalho Chehab 		.luma_control  = 0x40,
201b285192aSMauro Carvalho Chehab 		.chroma_ctrl1  = 0x81,
202b285192aSMauro Carvalho Chehab 		.chroma_gain   = 0x2a,
203b285192aSMauro Carvalho Chehab 		.chroma_ctrl2  = 0x06,
204b285192aSMauro Carvalho Chehab 		.vgate_misc    = 0x1c,
205b285192aSMauro Carvalho Chehab 
206b285192aSMauro Carvalho Chehab 	},{
207b285192aSMauro Carvalho Chehab 		.name          = "PAL-BG",
208b285192aSMauro Carvalho Chehab 		.id            = V4L2_STD_PAL_BG,
209b285192aSMauro Carvalho Chehab 		NORM_625_50,
210b285192aSMauro Carvalho Chehab 
211b285192aSMauro Carvalho Chehab 		.sync_control  = 0x18,
212b285192aSMauro Carvalho Chehab 		.luma_control  = 0x40,
213b285192aSMauro Carvalho Chehab 		.chroma_ctrl1  = 0x81,
214b285192aSMauro Carvalho Chehab 		.chroma_gain   = 0x2a,
215b285192aSMauro Carvalho Chehab 		.chroma_ctrl2  = 0x06,
216b285192aSMauro Carvalho Chehab 		.vgate_misc    = 0x1c,
217b285192aSMauro Carvalho Chehab 
218b285192aSMauro Carvalho Chehab 	},{
219b285192aSMauro Carvalho Chehab 		.name          = "PAL-I",
220b285192aSMauro Carvalho Chehab 		.id            = V4L2_STD_PAL_I,
221b285192aSMauro Carvalho Chehab 		NORM_625_50,
222b285192aSMauro Carvalho Chehab 
223b285192aSMauro Carvalho Chehab 		.sync_control  = 0x18,
224b285192aSMauro Carvalho Chehab 		.luma_control  = 0x40,
225b285192aSMauro Carvalho Chehab 		.chroma_ctrl1  = 0x81,
226b285192aSMauro Carvalho Chehab 		.chroma_gain   = 0x2a,
227b285192aSMauro Carvalho Chehab 		.chroma_ctrl2  = 0x06,
228b285192aSMauro Carvalho Chehab 		.vgate_misc    = 0x1c,
229b285192aSMauro Carvalho Chehab 
230b285192aSMauro Carvalho Chehab 	},{
231b285192aSMauro Carvalho Chehab 		.name          = "PAL-DK",
232b285192aSMauro Carvalho Chehab 		.id            = V4L2_STD_PAL_DK,
233b285192aSMauro Carvalho Chehab 		NORM_625_50,
234b285192aSMauro Carvalho Chehab 
235b285192aSMauro Carvalho Chehab 		.sync_control  = 0x18,
236b285192aSMauro Carvalho Chehab 		.luma_control  = 0x40,
237b285192aSMauro Carvalho Chehab 		.chroma_ctrl1  = 0x81,
238b285192aSMauro Carvalho Chehab 		.chroma_gain   = 0x2a,
239b285192aSMauro Carvalho Chehab 		.chroma_ctrl2  = 0x06,
240b285192aSMauro Carvalho Chehab 		.vgate_misc    = 0x1c,
241b285192aSMauro Carvalho Chehab 
242b285192aSMauro Carvalho Chehab 	},{
243b285192aSMauro Carvalho Chehab 		.name          = "NTSC",
244b285192aSMauro Carvalho Chehab 		.id            = V4L2_STD_NTSC,
245b285192aSMauro Carvalho Chehab 		NORM_525_60,
246b285192aSMauro Carvalho Chehab 
247b285192aSMauro Carvalho Chehab 		.sync_control  = 0x59,
248b285192aSMauro Carvalho Chehab 		.luma_control  = 0x40,
249b285192aSMauro Carvalho Chehab 		.chroma_ctrl1  = 0x89,
250b285192aSMauro Carvalho Chehab 		.chroma_gain   = 0x2a,
251b285192aSMauro Carvalho Chehab 		.chroma_ctrl2  = 0x0e,
252b285192aSMauro Carvalho Chehab 		.vgate_misc    = 0x18,
253b285192aSMauro Carvalho Chehab 
254b285192aSMauro Carvalho Chehab 	},{
255b285192aSMauro Carvalho Chehab 		.name          = "SECAM",
256b285192aSMauro Carvalho Chehab 		.id            = V4L2_STD_SECAM,
257b285192aSMauro Carvalho Chehab 		NORM_625_50,
258b285192aSMauro Carvalho Chehab 
259b285192aSMauro Carvalho Chehab 		.sync_control  = 0x18,
260b285192aSMauro Carvalho Chehab 		.luma_control  = 0x1b,
261b285192aSMauro Carvalho Chehab 		.chroma_ctrl1  = 0xd1,
262b285192aSMauro Carvalho Chehab 		.chroma_gain   = 0x80,
263b285192aSMauro Carvalho Chehab 		.chroma_ctrl2  = 0x00,
264b285192aSMauro Carvalho Chehab 		.vgate_misc    = 0x1c,
265b285192aSMauro Carvalho Chehab 
266b285192aSMauro Carvalho Chehab 	},{
267b285192aSMauro Carvalho Chehab 		.name          = "SECAM-DK",
268b285192aSMauro Carvalho Chehab 		.id            = V4L2_STD_SECAM_DK,
269b285192aSMauro Carvalho Chehab 		NORM_625_50,
270b285192aSMauro Carvalho Chehab 
271b285192aSMauro Carvalho Chehab 		.sync_control  = 0x18,
272b285192aSMauro Carvalho Chehab 		.luma_control  = 0x1b,
273b285192aSMauro Carvalho Chehab 		.chroma_ctrl1  = 0xd1,
274b285192aSMauro Carvalho Chehab 		.chroma_gain   = 0x80,
275b285192aSMauro Carvalho Chehab 		.chroma_ctrl2  = 0x00,
276b285192aSMauro Carvalho Chehab 		.vgate_misc    = 0x1c,
277b285192aSMauro Carvalho Chehab 
278b285192aSMauro Carvalho Chehab 	},{
279b285192aSMauro Carvalho Chehab 		.name          = "SECAM-L",
280b285192aSMauro Carvalho Chehab 		.id            = V4L2_STD_SECAM_L,
281b285192aSMauro Carvalho Chehab 		NORM_625_50,
282b285192aSMauro Carvalho Chehab 
283b285192aSMauro Carvalho Chehab 		.sync_control  = 0x18,
284b285192aSMauro Carvalho Chehab 		.luma_control  = 0x1b,
285b285192aSMauro Carvalho Chehab 		.chroma_ctrl1  = 0xd1,
286b285192aSMauro Carvalho Chehab 		.chroma_gain   = 0x80,
287b285192aSMauro Carvalho Chehab 		.chroma_ctrl2  = 0x00,
288b285192aSMauro Carvalho Chehab 		.vgate_misc    = 0x1c,
289b285192aSMauro Carvalho Chehab 
290b285192aSMauro Carvalho Chehab 	},{
291b285192aSMauro Carvalho Chehab 		.name          = "SECAM-Lc",
292b285192aSMauro Carvalho Chehab 		.id            = V4L2_STD_SECAM_LC,
293b285192aSMauro Carvalho Chehab 		NORM_625_50,
294b285192aSMauro Carvalho Chehab 
295b285192aSMauro Carvalho Chehab 		.sync_control  = 0x18,
296b285192aSMauro Carvalho Chehab 		.luma_control  = 0x1b,
297b285192aSMauro Carvalho Chehab 		.chroma_ctrl1  = 0xd1,
298b285192aSMauro Carvalho Chehab 		.chroma_gain   = 0x80,
299b285192aSMauro Carvalho Chehab 		.chroma_ctrl2  = 0x00,
300b285192aSMauro Carvalho Chehab 		.vgate_misc    = 0x1c,
301b285192aSMauro Carvalho Chehab 
302b285192aSMauro Carvalho Chehab 	},{
303b285192aSMauro Carvalho Chehab 		.name          = "PAL-M",
304b285192aSMauro Carvalho Chehab 		.id            = V4L2_STD_PAL_M,
305b285192aSMauro Carvalho Chehab 		NORM_525_60,
306b285192aSMauro Carvalho Chehab 
307b285192aSMauro Carvalho Chehab 		.sync_control  = 0x59,
308b285192aSMauro Carvalho Chehab 		.luma_control  = 0x40,
309b285192aSMauro Carvalho Chehab 		.chroma_ctrl1  = 0xb9,
310b285192aSMauro Carvalho Chehab 		.chroma_gain   = 0x2a,
311b285192aSMauro Carvalho Chehab 		.chroma_ctrl2  = 0x0e,
312b285192aSMauro Carvalho Chehab 		.vgate_misc    = 0x18,
313b285192aSMauro Carvalho Chehab 
314b285192aSMauro Carvalho Chehab 	},{
315b285192aSMauro Carvalho Chehab 		.name          = "PAL-Nc",
316b285192aSMauro Carvalho Chehab 		.id            = V4L2_STD_PAL_Nc,
317b285192aSMauro Carvalho Chehab 		NORM_625_50,
318b285192aSMauro Carvalho Chehab 
319b285192aSMauro Carvalho Chehab 		.sync_control  = 0x18,
320b285192aSMauro Carvalho Chehab 		.luma_control  = 0x40,
321b285192aSMauro Carvalho Chehab 		.chroma_ctrl1  = 0xa1,
322b285192aSMauro Carvalho Chehab 		.chroma_gain   = 0x2a,
323b285192aSMauro Carvalho Chehab 		.chroma_ctrl2  = 0x06,
324b285192aSMauro Carvalho Chehab 		.vgate_misc    = 0x1c,
325b285192aSMauro Carvalho Chehab 
326b285192aSMauro Carvalho Chehab 	},{
327b285192aSMauro Carvalho Chehab 		.name          = "PAL-60",
328b285192aSMauro Carvalho Chehab 		.id            = V4L2_STD_PAL_60,
329b285192aSMauro Carvalho Chehab 
330b285192aSMauro Carvalho Chehab 		.h_start       = 0,
331b285192aSMauro Carvalho Chehab 		.h_stop        = 719,
332b285192aSMauro Carvalho Chehab 		.video_v_start = 23,
333b285192aSMauro Carvalho Chehab 		.video_v_stop  = 262,
334b285192aSMauro Carvalho Chehab 		.vbi_v_start_0 = 10,
335b285192aSMauro Carvalho Chehab 		.vbi_v_stop_0  = 21,
336b285192aSMauro Carvalho Chehab 		.vbi_v_start_1 = 273,
337b285192aSMauro Carvalho Chehab 		.src_timing    = 7,
338b285192aSMauro Carvalho Chehab 
339b285192aSMauro Carvalho Chehab 		.sync_control  = 0x18,
340b285192aSMauro Carvalho Chehab 		.luma_control  = 0x40,
341b285192aSMauro Carvalho Chehab 		.chroma_ctrl1  = 0x81,
342b285192aSMauro Carvalho Chehab 		.chroma_gain   = 0x2a,
343b285192aSMauro Carvalho Chehab 		.chroma_ctrl2  = 0x06,
344b285192aSMauro Carvalho Chehab 		.vgate_misc    = 0x1c,
345b285192aSMauro Carvalho Chehab 	}
346b285192aSMauro Carvalho Chehab };
347b285192aSMauro Carvalho Chehab #define TVNORMS ARRAY_SIZE(tvnorms)
348b285192aSMauro Carvalho Chehab 
format_by_fourcc(unsigned int fourcc)349b285192aSMauro Carvalho Chehab static struct saa7134_format* format_by_fourcc(unsigned int fourcc)
350b285192aSMauro Carvalho Chehab {
351b285192aSMauro Carvalho Chehab 	unsigned int i;
352b285192aSMauro Carvalho Chehab 
353b285192aSMauro Carvalho Chehab 	for (i = 0; i < FORMATS; i++)
354b285192aSMauro Carvalho Chehab 		if (formats[i].fourcc == fourcc)
355b285192aSMauro Carvalho Chehab 			return formats+i;
356b285192aSMauro Carvalho Chehab 	return NULL;
357b285192aSMauro Carvalho Chehab }
358b285192aSMauro Carvalho Chehab 
359b285192aSMauro Carvalho Chehab /* ------------------------------------------------------------------ */
360b285192aSMauro Carvalho Chehab 
set_tvnorm(struct saa7134_dev * dev,struct saa7134_tvnorm * norm)361b285192aSMauro Carvalho Chehab static void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm)
362b285192aSMauro Carvalho Chehab {
363630983b7SMauro Carvalho Chehab 	video_dbg("set tv norm = %s\n", norm->name);
364b285192aSMauro Carvalho Chehab 	dev->tvnorm = norm;
365b285192aSMauro Carvalho Chehab 
366b285192aSMauro Carvalho Chehab 	/* setup cropping */
367b285192aSMauro Carvalho Chehab 	dev->crop_bounds.left    = norm->h_start;
368b285192aSMauro Carvalho Chehab 	dev->crop_defrect.left   = norm->h_start;
369b285192aSMauro Carvalho Chehab 	dev->crop_bounds.width   = norm->h_stop - norm->h_start +1;
370b285192aSMauro Carvalho Chehab 	dev->crop_defrect.width  = norm->h_stop - norm->h_start +1;
371b285192aSMauro Carvalho Chehab 
372b285192aSMauro Carvalho Chehab 	dev->crop_bounds.top     = (norm->vbi_v_stop_0+1)*2;
373b285192aSMauro Carvalho Chehab 	dev->crop_defrect.top    = norm->video_v_start*2;
374b285192aSMauro Carvalho Chehab 	dev->crop_bounds.height  = ((norm->id & V4L2_STD_525_60) ? 524 : 624)
375b285192aSMauro Carvalho Chehab 		- dev->crop_bounds.top;
376b285192aSMauro Carvalho Chehab 	dev->crop_defrect.height = (norm->video_v_stop - norm->video_v_start +1)*2;
377b285192aSMauro Carvalho Chehab 
378b285192aSMauro Carvalho Chehab 	dev->crop_current = dev->crop_defrect;
379b285192aSMauro Carvalho Chehab 
380b285192aSMauro Carvalho Chehab 	saa7134_set_tvnorm_hw(dev);
381b285192aSMauro Carvalho Chehab }
382b285192aSMauro Carvalho Chehab 
video_mux(struct saa7134_dev * dev,int input)383b285192aSMauro Carvalho Chehab static void video_mux(struct saa7134_dev *dev, int input)
384b285192aSMauro Carvalho Chehab {
3858fc34867SMauro Carvalho Chehab 	video_dbg("video input = %d [%s]\n",
3868fc34867SMauro Carvalho Chehab 		  input, saa7134_input_name[card_in(dev, input).type]);
387b285192aSMauro Carvalho Chehab 	dev->ctl_input = input;
388b285192aSMauro Carvalho Chehab 	set_tvnorm(dev, dev->tvnorm);
389b285192aSMauro Carvalho Chehab 	saa7134_tvaudio_setinput(dev, &card_in(dev, input));
390b285192aSMauro Carvalho Chehab }
391b285192aSMauro Carvalho Chehab 
392b285192aSMauro Carvalho Chehab 
saa7134_set_decoder(struct saa7134_dev * dev)393b285192aSMauro Carvalho Chehab static void saa7134_set_decoder(struct saa7134_dev *dev)
394b285192aSMauro Carvalho Chehab {
395707b7f80SMikhail Domrachev 	int luma_control, sync_control, chroma_ctrl1, mux;
396b285192aSMauro Carvalho Chehab 
397b285192aSMauro Carvalho Chehab 	struct saa7134_tvnorm *norm = dev->tvnorm;
398b285192aSMauro Carvalho Chehab 	mux = card_in(dev, dev->ctl_input).vmux;
399b285192aSMauro Carvalho Chehab 
400b285192aSMauro Carvalho Chehab 	luma_control = norm->luma_control;
401b285192aSMauro Carvalho Chehab 	sync_control = norm->sync_control;
402707b7f80SMikhail Domrachev 	chroma_ctrl1 = norm->chroma_ctrl1;
403b285192aSMauro Carvalho Chehab 
404b285192aSMauro Carvalho Chehab 	if (mux > 5)
405b285192aSMauro Carvalho Chehab 		luma_control |= 0x80; /* svideo */
406b285192aSMauro Carvalho Chehab 	if (noninterlaced || dev->nosignal)
407b285192aSMauro Carvalho Chehab 		sync_control |= 0x20;
408b285192aSMauro Carvalho Chehab 
409707b7f80SMikhail Domrachev 	/* switch on auto standard detection */
410707b7f80SMikhail Domrachev 	sync_control |= SAA7134_SYNC_CTRL_AUFD;
411707b7f80SMikhail Domrachev 	chroma_ctrl1 |= SAA7134_CHROMA_CTRL1_AUTO0;
412707b7f80SMikhail Domrachev 	chroma_ctrl1 &= ~SAA7134_CHROMA_CTRL1_FCTC;
413707b7f80SMikhail Domrachev 	luma_control &= ~SAA7134_LUMA_CTRL_LDEL;
414707b7f80SMikhail Domrachev 
415b285192aSMauro Carvalho Chehab 	/* setup video decoder */
416b285192aSMauro Carvalho Chehab 	saa_writeb(SAA7134_INCR_DELAY,            0x08);
417b285192aSMauro Carvalho Chehab 	saa_writeb(SAA7134_ANALOG_IN_CTRL1,       0xc0 | mux);
418b285192aSMauro Carvalho Chehab 	saa_writeb(SAA7134_ANALOG_IN_CTRL2,       0x00);
419b285192aSMauro Carvalho Chehab 
420b285192aSMauro Carvalho Chehab 	saa_writeb(SAA7134_ANALOG_IN_CTRL3,       0x90);
421b285192aSMauro Carvalho Chehab 	saa_writeb(SAA7134_ANALOG_IN_CTRL4,       0x90);
422b285192aSMauro Carvalho Chehab 	saa_writeb(SAA7134_HSYNC_START,           0xeb);
423b285192aSMauro Carvalho Chehab 	saa_writeb(SAA7134_HSYNC_STOP,            0xe0);
424b285192aSMauro Carvalho Chehab 	saa_writeb(SAA7134_SOURCE_TIMING1,        norm->src_timing);
425b285192aSMauro Carvalho Chehab 
426b285192aSMauro Carvalho Chehab 	saa_writeb(SAA7134_SYNC_CTRL,             sync_control);
427b285192aSMauro Carvalho Chehab 	saa_writeb(SAA7134_LUMA_CTRL,             luma_control);
428b285192aSMauro Carvalho Chehab 	saa_writeb(SAA7134_DEC_LUMA_BRIGHT,       dev->ctl_bright);
429b285192aSMauro Carvalho Chehab 
430b285192aSMauro Carvalho Chehab 	saa_writeb(SAA7134_DEC_LUMA_CONTRAST,
431b285192aSMauro Carvalho Chehab 		dev->ctl_invert ? -dev->ctl_contrast : dev->ctl_contrast);
432b285192aSMauro Carvalho Chehab 
433b285192aSMauro Carvalho Chehab 	saa_writeb(SAA7134_DEC_CHROMA_SATURATION,
434b285192aSMauro Carvalho Chehab 		dev->ctl_invert ? -dev->ctl_saturation : dev->ctl_saturation);
435b285192aSMauro Carvalho Chehab 
436b285192aSMauro Carvalho Chehab 	saa_writeb(SAA7134_DEC_CHROMA_HUE,        dev->ctl_hue);
437707b7f80SMikhail Domrachev 	saa_writeb(SAA7134_CHROMA_CTRL1,          chroma_ctrl1);
438b285192aSMauro Carvalho Chehab 	saa_writeb(SAA7134_CHROMA_GAIN,           norm->chroma_gain);
439b285192aSMauro Carvalho Chehab 
440b285192aSMauro Carvalho Chehab 	saa_writeb(SAA7134_CHROMA_CTRL2,          norm->chroma_ctrl2);
441b285192aSMauro Carvalho Chehab 	saa_writeb(SAA7134_MODE_DELAY_CTRL,       0x00);
442b285192aSMauro Carvalho Chehab 
443b285192aSMauro Carvalho Chehab 	saa_writeb(SAA7134_ANALOG_ADC,            0x01);
444b285192aSMauro Carvalho Chehab 	saa_writeb(SAA7134_VGATE_START,           0x11);
445b285192aSMauro Carvalho Chehab 	saa_writeb(SAA7134_VGATE_STOP,            0xfe);
446b285192aSMauro Carvalho Chehab 	saa_writeb(SAA7134_MISC_VGATE_MSB,        norm->vgate_misc);
447b285192aSMauro Carvalho Chehab 	saa_writeb(SAA7134_RAW_DATA_GAIN,         0x40);
448b285192aSMauro Carvalho Chehab 	saa_writeb(SAA7134_RAW_DATA_OFFSET,       0x80);
449b285192aSMauro Carvalho Chehab }
450b285192aSMauro Carvalho Chehab 
saa7134_set_tvnorm_hw(struct saa7134_dev * dev)451b285192aSMauro Carvalho Chehab void saa7134_set_tvnorm_hw(struct saa7134_dev *dev)
452b285192aSMauro Carvalho Chehab {
453b285192aSMauro Carvalho Chehab 	saa7134_set_decoder(dev);
454b285192aSMauro Carvalho Chehab 
4558774bed9SLaurent Pinchart 	saa_call_all(dev, video, s_std, dev->tvnorm->id);
456b285192aSMauro Carvalho Chehab 	/* Set the correct norm for the saa6752hs. This function
457b285192aSMauro Carvalho Chehab 	   does nothing if there is no saa6752hs. */
4588774bed9SLaurent Pinchart 	saa_call_empress(dev, video, s_std, dev->tvnorm->id);
459b285192aSMauro Carvalho Chehab }
460b285192aSMauro Carvalho Chehab 
set_h_prescale(struct saa7134_dev * dev,int task,int prescale)461b285192aSMauro Carvalho Chehab static void set_h_prescale(struct saa7134_dev *dev, int task, int prescale)
462b285192aSMauro Carvalho Chehab {
463b285192aSMauro Carvalho Chehab 	static const struct {
464b285192aSMauro Carvalho Chehab 		int xpsc;
465b285192aSMauro Carvalho Chehab 		int xacl;
466b285192aSMauro Carvalho Chehab 		int xc2_1;
467b285192aSMauro Carvalho Chehab 		int xdcg;
468b285192aSMauro Carvalho Chehab 		int vpfy;
469b285192aSMauro Carvalho Chehab 	} vals[] = {
470b285192aSMauro Carvalho Chehab 		/* XPSC XACL XC2_1 XDCG VPFY */
471b285192aSMauro Carvalho Chehab 		{    1,   0,    0,    0,   0 },
472b285192aSMauro Carvalho Chehab 		{    2,   2,    1,    2,   2 },
473b285192aSMauro Carvalho Chehab 		{    3,   4,    1,    3,   2 },
474b285192aSMauro Carvalho Chehab 		{    4,   8,    1,    4,   2 },
475b285192aSMauro Carvalho Chehab 		{    5,   8,    1,    4,   2 },
476b285192aSMauro Carvalho Chehab 		{    6,   8,    1,    4,   3 },
477b285192aSMauro Carvalho Chehab 		{    7,   8,    1,    4,   3 },
478b285192aSMauro Carvalho Chehab 		{    8,  15,    0,    4,   3 },
479b285192aSMauro Carvalho Chehab 		{    9,  15,    0,    4,   3 },
480b285192aSMauro Carvalho Chehab 		{   10,  16,    1,    5,   3 },
481b285192aSMauro Carvalho Chehab 	};
482b285192aSMauro Carvalho Chehab 	static const int count = ARRAY_SIZE(vals);
483b285192aSMauro Carvalho Chehab 	int i;
484b285192aSMauro Carvalho Chehab 
485b285192aSMauro Carvalho Chehab 	for (i = 0; i < count; i++)
486b285192aSMauro Carvalho Chehab 		if (vals[i].xpsc == prescale)
487b285192aSMauro Carvalho Chehab 			break;
488b285192aSMauro Carvalho Chehab 	if (i == count)
489b285192aSMauro Carvalho Chehab 		return;
490b285192aSMauro Carvalho Chehab 
491b285192aSMauro Carvalho Chehab 	saa_writeb(SAA7134_H_PRESCALE(task), vals[i].xpsc);
492b285192aSMauro Carvalho Chehab 	saa_writeb(SAA7134_ACC_LENGTH(task), vals[i].xacl);
493b285192aSMauro Carvalho Chehab 	saa_writeb(SAA7134_LEVEL_CTRL(task),
494b285192aSMauro Carvalho Chehab 		   (vals[i].xc2_1 << 3) | (vals[i].xdcg));
495b285192aSMauro Carvalho Chehab 	saa_andorb(SAA7134_FIR_PREFILTER_CTRL(task), 0x0f,
496b285192aSMauro Carvalho Chehab 		   (vals[i].vpfy << 2) | vals[i].vpfy);
497b285192aSMauro Carvalho Chehab }
498b285192aSMauro Carvalho Chehab 
set_v_scale(struct saa7134_dev * dev,int task,int yscale)499b285192aSMauro Carvalho Chehab static void set_v_scale(struct saa7134_dev *dev, int task, int yscale)
500b285192aSMauro Carvalho Chehab {
501b285192aSMauro Carvalho Chehab 	int val,mirror;
502b285192aSMauro Carvalho Chehab 
503b285192aSMauro Carvalho Chehab 	saa_writeb(SAA7134_V_SCALE_RATIO1(task), yscale &  0xff);
504b285192aSMauro Carvalho Chehab 	saa_writeb(SAA7134_V_SCALE_RATIO2(task), yscale >> 8);
505b285192aSMauro Carvalho Chehab 
506b285192aSMauro Carvalho Chehab 	mirror = (dev->ctl_mirror) ? 0x02 : 0x00;
507b285192aSMauro Carvalho Chehab 	if (yscale < 2048) {
508b285192aSMauro Carvalho Chehab 		/* LPI */
509630983b7SMauro Carvalho Chehab 		video_dbg("yscale LPI yscale=%d\n", yscale);
510b285192aSMauro Carvalho Chehab 		saa_writeb(SAA7134_V_FILTER(task), 0x00 | mirror);
511b285192aSMauro Carvalho Chehab 		saa_writeb(SAA7134_LUMA_CONTRAST(task), 0x40);
512b285192aSMauro Carvalho Chehab 		saa_writeb(SAA7134_CHROMA_SATURATION(task), 0x40);
513b285192aSMauro Carvalho Chehab 	} else {
514b285192aSMauro Carvalho Chehab 		/* ACM */
515b285192aSMauro Carvalho Chehab 		val = 0x40 * 1024 / yscale;
516630983b7SMauro Carvalho Chehab 		video_dbg("yscale ACM yscale=%d val=0x%x\n", yscale, val);
517b285192aSMauro Carvalho Chehab 		saa_writeb(SAA7134_V_FILTER(task), 0x01 | mirror);
518b285192aSMauro Carvalho Chehab 		saa_writeb(SAA7134_LUMA_CONTRAST(task), val);
519b285192aSMauro Carvalho Chehab 		saa_writeb(SAA7134_CHROMA_SATURATION(task), val);
520b285192aSMauro Carvalho Chehab 	}
521b285192aSMauro Carvalho Chehab 	saa_writeb(SAA7134_LUMA_BRIGHT(task),       0x80);
522b285192aSMauro Carvalho Chehab }
523b285192aSMauro Carvalho Chehab 
set_size(struct saa7134_dev * dev,int task,int width,int height,int interlace)524b285192aSMauro Carvalho Chehab static void set_size(struct saa7134_dev *dev, int task,
525b285192aSMauro Carvalho Chehab 		     int width, int height, int interlace)
526b285192aSMauro Carvalho Chehab {
527b285192aSMauro Carvalho Chehab 	int prescale,xscale,yscale,y_even,y_odd;
528b285192aSMauro Carvalho Chehab 	int h_start, h_stop, v_start, v_stop;
529b285192aSMauro Carvalho Chehab 	int div = interlace ? 2 : 1;
530b285192aSMauro Carvalho Chehab 
531b285192aSMauro Carvalho Chehab 	/* setup video scaler */
532b285192aSMauro Carvalho Chehab 	h_start = dev->crop_current.left;
533b285192aSMauro Carvalho Chehab 	v_start = dev->crop_current.top/2;
534b285192aSMauro Carvalho Chehab 	h_stop  = (dev->crop_current.left + dev->crop_current.width -1);
535b285192aSMauro Carvalho Chehab 	v_stop  = (dev->crop_current.top + dev->crop_current.height -1)/2;
536b285192aSMauro Carvalho Chehab 
537b285192aSMauro Carvalho Chehab 	saa_writeb(SAA7134_VIDEO_H_START1(task), h_start &  0xff);
538b285192aSMauro Carvalho Chehab 	saa_writeb(SAA7134_VIDEO_H_START2(task), h_start >> 8);
539b285192aSMauro Carvalho Chehab 	saa_writeb(SAA7134_VIDEO_H_STOP1(task),  h_stop  &  0xff);
540b285192aSMauro Carvalho Chehab 	saa_writeb(SAA7134_VIDEO_H_STOP2(task),  h_stop  >> 8);
541b285192aSMauro Carvalho Chehab 	saa_writeb(SAA7134_VIDEO_V_START1(task), v_start &  0xff);
542b285192aSMauro Carvalho Chehab 	saa_writeb(SAA7134_VIDEO_V_START2(task), v_start >> 8);
543b285192aSMauro Carvalho Chehab 	saa_writeb(SAA7134_VIDEO_V_STOP1(task),  v_stop  &  0xff);
544b285192aSMauro Carvalho Chehab 	saa_writeb(SAA7134_VIDEO_V_STOP2(task),  v_stop  >> 8);
545b285192aSMauro Carvalho Chehab 
546b285192aSMauro Carvalho Chehab 	prescale = dev->crop_current.width / width;
547b285192aSMauro Carvalho Chehab 	if (0 == prescale)
548b285192aSMauro Carvalho Chehab 		prescale = 1;
549b285192aSMauro Carvalho Chehab 	xscale = 1024 * dev->crop_current.width / prescale / width;
550b285192aSMauro Carvalho Chehab 	yscale = 512 * div * dev->crop_current.height / height;
5516139ebc6SMauro Carvalho Chehab 	video_dbg("prescale=%d xscale=%d yscale=%d\n",
5526139ebc6SMauro Carvalho Chehab 		  prescale, xscale, yscale);
553b285192aSMauro Carvalho Chehab 	set_h_prescale(dev,task,prescale);
554b285192aSMauro Carvalho Chehab 	saa_writeb(SAA7134_H_SCALE_INC1(task),      xscale &  0xff);
555b285192aSMauro Carvalho Chehab 	saa_writeb(SAA7134_H_SCALE_INC2(task),      xscale >> 8);
556b285192aSMauro Carvalho Chehab 	set_v_scale(dev,task,yscale);
557b285192aSMauro Carvalho Chehab 
558b285192aSMauro Carvalho Chehab 	saa_writeb(SAA7134_VIDEO_PIXELS1(task),     width  & 0xff);
559b285192aSMauro Carvalho Chehab 	saa_writeb(SAA7134_VIDEO_PIXELS2(task),     width  >> 8);
560b285192aSMauro Carvalho Chehab 	saa_writeb(SAA7134_VIDEO_LINES1(task),      height/div & 0xff);
561b285192aSMauro Carvalho Chehab 	saa_writeb(SAA7134_VIDEO_LINES2(task),      height/div >> 8);
562b285192aSMauro Carvalho Chehab 
563b285192aSMauro Carvalho Chehab 	/* deinterlace y offsets */
564b285192aSMauro Carvalho Chehab 	y_odd  = dev->ctl_y_odd;
565b285192aSMauro Carvalho Chehab 	y_even = dev->ctl_y_even;
566b285192aSMauro Carvalho Chehab 	saa_writeb(SAA7134_V_PHASE_OFFSET0(task), y_odd);
567b285192aSMauro Carvalho Chehab 	saa_writeb(SAA7134_V_PHASE_OFFSET1(task), y_even);
568b285192aSMauro Carvalho Chehab 	saa_writeb(SAA7134_V_PHASE_OFFSET2(task), y_odd);
569b285192aSMauro Carvalho Chehab 	saa_writeb(SAA7134_V_PHASE_OFFSET3(task), y_even);
570b285192aSMauro Carvalho Chehab }
571b285192aSMauro Carvalho Chehab 
572b285192aSMauro Carvalho Chehab /* ------------------------------------------------------------------ */
573b285192aSMauro Carvalho Chehab 
574ac90aa02SMauro Carvalho Chehab /*
575ac90aa02SMauro Carvalho Chehab  * Media Controller helper functions
576ac90aa02SMauro Carvalho Chehab  */
577ac90aa02SMauro Carvalho Chehab 
saa7134_enable_analog_tuner(struct saa7134_dev * dev)578ac90aa02SMauro Carvalho Chehab static int saa7134_enable_analog_tuner(struct saa7134_dev *dev)
579ac90aa02SMauro Carvalho Chehab {
580ac90aa02SMauro Carvalho Chehab #ifdef CONFIG_MEDIA_CONTROLLER
581ac90aa02SMauro Carvalho Chehab 	struct media_device *mdev = dev->media_dev;
582ac90aa02SMauro Carvalho Chehab 	struct media_entity *source;
583ac90aa02SMauro Carvalho Chehab 	struct media_link *link, *found_link = NULL;
584ac90aa02SMauro Carvalho Chehab 	int ret, active_links = 0;
585ac90aa02SMauro Carvalho Chehab 
586ac90aa02SMauro Carvalho Chehab 	if (!mdev || !dev->decoder)
587ac90aa02SMauro Carvalho Chehab 		return 0;
588ac90aa02SMauro Carvalho Chehab 
589ac90aa02SMauro Carvalho Chehab 	/*
590ac90aa02SMauro Carvalho Chehab 	 * This will find the tuner that is connected into the decoder.
591ac90aa02SMauro Carvalho Chehab 	 * Technically, this is not 100% correct, as the device may be
592ac90aa02SMauro Carvalho Chehab 	 * using an analog input instead of the tuner. However, as we can't
593ac90aa02SMauro Carvalho Chehab 	 * do DVB streaming while the DMA engine is being used for V4L2,
594ac90aa02SMauro Carvalho Chehab 	 * this should be enough for the actual needs.
595ac90aa02SMauro Carvalho Chehab 	 */
596ac90aa02SMauro Carvalho Chehab 	list_for_each_entry(link, &dev->decoder->links, list) {
597ac90aa02SMauro Carvalho Chehab 		if (link->sink->entity == dev->decoder) {
598ac90aa02SMauro Carvalho Chehab 			found_link = link;
599ac90aa02SMauro Carvalho Chehab 			if (link->flags & MEDIA_LNK_FL_ENABLED)
600ac90aa02SMauro Carvalho Chehab 				active_links++;
601ac90aa02SMauro Carvalho Chehab 			break;
602ac90aa02SMauro Carvalho Chehab 		}
603ac90aa02SMauro Carvalho Chehab 	}
604ac90aa02SMauro Carvalho Chehab 
605ac90aa02SMauro Carvalho Chehab 	if (active_links == 1 || !found_link)
606ac90aa02SMauro Carvalho Chehab 		return 0;
607ac90aa02SMauro Carvalho Chehab 
608ac90aa02SMauro Carvalho Chehab 	source = found_link->source->entity;
609ac90aa02SMauro Carvalho Chehab 	list_for_each_entry(link, &source->links, list) {
610ac90aa02SMauro Carvalho Chehab 		struct media_entity *sink;
611ac90aa02SMauro Carvalho Chehab 		int flags = 0;
612ac90aa02SMauro Carvalho Chehab 
613ac90aa02SMauro Carvalho Chehab 		sink = link->sink->entity;
614ac90aa02SMauro Carvalho Chehab 
615ac90aa02SMauro Carvalho Chehab 		if (sink == dev->decoder)
616ac90aa02SMauro Carvalho Chehab 			flags = MEDIA_LNK_FL_ENABLED;
617ac90aa02SMauro Carvalho Chehab 
618ac90aa02SMauro Carvalho Chehab 		ret = media_entity_setup_link(link, flags);
619ac90aa02SMauro Carvalho Chehab 		if (ret) {
620ac90aa02SMauro Carvalho Chehab 			pr_err("Couldn't change link %s->%s to %s. Error %d\n",
621ac90aa02SMauro Carvalho Chehab 			       source->name, sink->name,
622ac90aa02SMauro Carvalho Chehab 			       flags ? "enabled" : "disabled",
623ac90aa02SMauro Carvalho Chehab 			       ret);
624ac90aa02SMauro Carvalho Chehab 			return ret;
625ac90aa02SMauro Carvalho Chehab 		}
626ac90aa02SMauro Carvalho Chehab 	}
627ac90aa02SMauro Carvalho Chehab #endif
628ac90aa02SMauro Carvalho Chehab 	return 0;
629ac90aa02SMauro Carvalho Chehab }
630ac90aa02SMauro Carvalho Chehab 
631b285192aSMauro Carvalho Chehab /* ------------------------------------------------------------------ */
632b285192aSMauro Carvalho Chehab 
buffer_activate(struct saa7134_dev * dev,struct saa7134_buf * buf,struct saa7134_buf * next)633b285192aSMauro Carvalho Chehab static int buffer_activate(struct saa7134_dev *dev,
634b285192aSMauro Carvalho Chehab 			   struct saa7134_buf *buf,
635b285192aSMauro Carvalho Chehab 			   struct saa7134_buf *next)
636b285192aSMauro Carvalho Chehab {
6372d700715SJunghak Sung 	struct saa7134_dmaqueue *dmaq = buf->vb2.vb2_buf.vb2_queue->drv_priv;
638b285192aSMauro Carvalho Chehab 	unsigned long base,control,bpl;
639d8772818SYang Guang 	unsigned long bpl_uv, lines_uv, base2, base3; /* planar */
640b285192aSMauro Carvalho Chehab 
641630983b7SMauro Carvalho Chehab 	video_dbg("buffer_activate buf=%p\n", buf);
642b285192aSMauro Carvalho Chehab 	buf->top_seen = 0;
643b285192aSMauro Carvalho Chehab 
6442ada815fSHans Verkuil 	set_size(dev, TASK_A, dev->width, dev->height,
6452ada815fSHans Verkuil 		 V4L2_FIELD_HAS_BOTH(dev->field));
6469e534f84SHans Verkuil 	if (dev->fmt->yuv)
647b285192aSMauro Carvalho Chehab 		saa_andorb(SAA7134_DATA_PATH(TASK_A), 0x3f, 0x03);
648b285192aSMauro Carvalho Chehab 	else
649b285192aSMauro Carvalho Chehab 		saa_andorb(SAA7134_DATA_PATH(TASK_A), 0x3f, 0x01);
6509e534f84SHans Verkuil 	saa_writeb(SAA7134_OFMT_VIDEO_A, dev->fmt->pm);
651b285192aSMauro Carvalho Chehab 
652b285192aSMauro Carvalho Chehab 	/* DMA: setup channel 0 (= Video Task A0) */
653b285192aSMauro Carvalho Chehab 	base  = saa7134_buffer_base(buf);
6549e534f84SHans Verkuil 	if (dev->fmt->planar)
6552ada815fSHans Verkuil 		bpl = dev->width;
656b285192aSMauro Carvalho Chehab 	else
6572ada815fSHans Verkuil 		bpl = (dev->width * dev->fmt->depth) / 8;
658b285192aSMauro Carvalho Chehab 	control = SAA7134_RS_CONTROL_BURST_16 |
659b285192aSMauro Carvalho Chehab 		SAA7134_RS_CONTROL_ME |
6602ada815fSHans Verkuil 		(dmaq->pt.dma >> 12);
6619e534f84SHans Verkuil 	if (dev->fmt->bswap)
662b285192aSMauro Carvalho Chehab 		control |= SAA7134_RS_CONTROL_BSWAP;
6639e534f84SHans Verkuil 	if (dev->fmt->wswap)
664b285192aSMauro Carvalho Chehab 		control |= SAA7134_RS_CONTROL_WSWAP;
6652ada815fSHans Verkuil 	if (V4L2_FIELD_HAS_BOTH(dev->field)) {
666b285192aSMauro Carvalho Chehab 		/* interlaced */
667b285192aSMauro Carvalho Chehab 		saa_writel(SAA7134_RS_BA1(0),base);
668b285192aSMauro Carvalho Chehab 		saa_writel(SAA7134_RS_BA2(0),base+bpl);
669b285192aSMauro Carvalho Chehab 		saa_writel(SAA7134_RS_PITCH(0),bpl*2);
670b285192aSMauro Carvalho Chehab 	} else {
671b285192aSMauro Carvalho Chehab 		/* non-interlaced */
672b285192aSMauro Carvalho Chehab 		saa_writel(SAA7134_RS_BA1(0),base);
673b285192aSMauro Carvalho Chehab 		saa_writel(SAA7134_RS_BA2(0),base);
674b285192aSMauro Carvalho Chehab 		saa_writel(SAA7134_RS_PITCH(0),bpl);
675b285192aSMauro Carvalho Chehab 	}
676b285192aSMauro Carvalho Chehab 	saa_writel(SAA7134_RS_CONTROL(0),control);
677b285192aSMauro Carvalho Chehab 
6789e534f84SHans Verkuil 	if (dev->fmt->planar) {
679b285192aSMauro Carvalho Chehab 		/* DMA: setup channel 4+5 (= planar task A) */
6809e534f84SHans Verkuil 		bpl_uv   = bpl >> dev->fmt->hshift;
6812ada815fSHans Verkuil 		lines_uv = dev->height >> dev->fmt->vshift;
6822ada815fSHans Verkuil 		base2    = base + bpl * dev->height;
683b285192aSMauro Carvalho Chehab 		base3    = base2 + bpl_uv * lines_uv;
684d8772818SYang Guang 		if (dev->fmt->uvswap)
685d8772818SYang Guang 			swap(base2, base3);
686630983b7SMauro Carvalho Chehab 		video_dbg("uv: bpl=%ld lines=%ld base2/3=%ld/%ld\n",
687b285192aSMauro Carvalho Chehab 			bpl_uv,lines_uv,base2,base3);
6882ada815fSHans Verkuil 		if (V4L2_FIELD_HAS_BOTH(dev->field)) {
689b285192aSMauro Carvalho Chehab 			/* interlaced */
690b285192aSMauro Carvalho Chehab 			saa_writel(SAA7134_RS_BA1(4),base2);
691b285192aSMauro Carvalho Chehab 			saa_writel(SAA7134_RS_BA2(4),base2+bpl_uv);
692b285192aSMauro Carvalho Chehab 			saa_writel(SAA7134_RS_PITCH(4),bpl_uv*2);
693b285192aSMauro Carvalho Chehab 			saa_writel(SAA7134_RS_BA1(5),base3);
694b285192aSMauro Carvalho Chehab 			saa_writel(SAA7134_RS_BA2(5),base3+bpl_uv);
695b285192aSMauro Carvalho Chehab 			saa_writel(SAA7134_RS_PITCH(5),bpl_uv*2);
696b285192aSMauro Carvalho Chehab 		} else {
697b285192aSMauro Carvalho Chehab 			/* non-interlaced */
698b285192aSMauro Carvalho Chehab 			saa_writel(SAA7134_RS_BA1(4),base2);
699b285192aSMauro Carvalho Chehab 			saa_writel(SAA7134_RS_BA2(4),base2);
700b285192aSMauro Carvalho Chehab 			saa_writel(SAA7134_RS_PITCH(4),bpl_uv);
701b285192aSMauro Carvalho Chehab 			saa_writel(SAA7134_RS_BA1(5),base3);
702b285192aSMauro Carvalho Chehab 			saa_writel(SAA7134_RS_BA2(5),base3);
703b285192aSMauro Carvalho Chehab 			saa_writel(SAA7134_RS_PITCH(5),bpl_uv);
704b285192aSMauro Carvalho Chehab 		}
705b285192aSMauro Carvalho Chehab 		saa_writel(SAA7134_RS_CONTROL(4),control);
706b285192aSMauro Carvalho Chehab 		saa_writel(SAA7134_RS_CONTROL(5),control);
707b285192aSMauro Carvalho Chehab 	}
708b285192aSMauro Carvalho Chehab 
709b285192aSMauro Carvalho Chehab 	/* start DMA */
710b285192aSMauro Carvalho Chehab 	saa7134_set_dmabits(dev);
7112ada815fSHans Verkuil 	mod_timer(&dmaq->timeout, jiffies + BUFFER_TIMEOUT);
712b285192aSMauro Carvalho Chehab 	return 0;
713b285192aSMauro Carvalho Chehab }
714b285192aSMauro Carvalho Chehab 
buffer_init(struct vb2_buffer * vb2)7152ada815fSHans Verkuil static int buffer_init(struct vb2_buffer *vb2)
716b285192aSMauro Carvalho Chehab {
7172ada815fSHans Verkuil 	struct saa7134_dmaqueue *dmaq = vb2->vb2_queue->drv_priv;
7182d700715SJunghak Sung 	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb2);
7192d700715SJunghak Sung 	struct saa7134_buf *buf = container_of(vbuf, struct saa7134_buf, vb2);
720b285192aSMauro Carvalho Chehab 
7212ada815fSHans Verkuil 	dmaq->curr = NULL;
7222ada815fSHans Verkuil 	buf->activate = buffer_activate;
7232ada815fSHans Verkuil 	return 0;
7242ada815fSHans Verkuil }
7252ada815fSHans Verkuil 
buffer_prepare(struct vb2_buffer * vb2)7262ada815fSHans Verkuil static int buffer_prepare(struct vb2_buffer *vb2)
7272ada815fSHans Verkuil {
7282ada815fSHans Verkuil 	struct saa7134_dmaqueue *dmaq = vb2->vb2_queue->drv_priv;
7292ada815fSHans Verkuil 	struct saa7134_dev *dev = dmaq->dev;
7302d700715SJunghak Sung 	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb2);
7312d700715SJunghak Sung 	struct saa7134_buf *buf = container_of(vbuf, struct saa7134_buf, vb2);
7322d700715SJunghak Sung 	struct sg_table *dma = vb2_dma_sg_plane_desc(vb2, 0);
7332ada815fSHans Verkuil 	unsigned int size;
7342ada815fSHans Verkuil 
735a3f415abSHans Verkuil 	if (dma->sgl->offset) {
736a3f415abSHans Verkuil 		pr_err("The buffer is not page-aligned\n");
737a3f415abSHans Verkuil 		return -EINVAL;
738a3f415abSHans Verkuil 	}
7392ada815fSHans Verkuil 	size = (dev->width * dev->height * dev->fmt->depth) >> 3;
7402ada815fSHans Verkuil 	if (vb2_plane_size(vb2, 0) < size)
741b285192aSMauro Carvalho Chehab 		return -EINVAL;
7422ada815fSHans Verkuil 
7432ada815fSHans Verkuil 	vb2_set_plane_payload(vb2, 0, size);
7442d700715SJunghak Sung 	vbuf->field = dev->field;
7452ada815fSHans Verkuil 
7462ada815fSHans Verkuil 	return saa7134_pgtable_build(dev->pci, &dmaq->pt, dma->sgl, dma->nents,
7472ada815fSHans Verkuil 				    saa7134_buffer_startpage(buf));
7482ada815fSHans Verkuil }
7492ada815fSHans Verkuil 
queue_setup(struct vb2_queue * q,unsigned int * nbuffers,unsigned int * nplanes,unsigned int sizes[],struct device * alloc_devs[])750df9ecb0cSHans Verkuil static int queue_setup(struct vb2_queue *q,
7512ada815fSHans Verkuil 			   unsigned int *nbuffers, unsigned int *nplanes,
75236c0f8b3SHans Verkuil 			   unsigned int sizes[], struct device *alloc_devs[])
7532ada815fSHans Verkuil {
7542ada815fSHans Verkuil 	struct saa7134_dmaqueue *dmaq = q->drv_priv;
7552ada815fSHans Verkuil 	struct saa7134_dev *dev = dmaq->dev;
7562ada815fSHans Verkuil 	int size = dev->fmt->depth * dev->width * dev->height >> 3;
7572ada815fSHans Verkuil 
758813b9dffSHans Verkuil 	if (dev->width    < 48 ||
759813b9dffSHans Verkuil 	    dev->height   < 32 ||
760813b9dffSHans Verkuil 	    dev->width/4  > dev->crop_current.width  ||
761813b9dffSHans Verkuil 	    dev->height/4 > dev->crop_current.height ||
762813b9dffSHans Verkuil 	    dev->width    > dev->crop_bounds.width  ||
763813b9dffSHans Verkuil 	    dev->height   > dev->crop_bounds.height)
764b285192aSMauro Carvalho Chehab 		return -EINVAL;
765b285192aSMauro Carvalho Chehab 
7662ada815fSHans Verkuil 	*nbuffers = saa7134_buffer_count(size, *nbuffers);
7672ada815fSHans Verkuil 	*nplanes = 1;
7682ada815fSHans Verkuil 	sizes[0] = size;
769ac90aa02SMauro Carvalho Chehab 
770ac90aa02SMauro Carvalho Chehab 	saa7134_enable_analog_tuner(dev);
771ac90aa02SMauro Carvalho Chehab 
772b285192aSMauro Carvalho Chehab 	return 0;
773b285192aSMauro Carvalho Chehab }
774b285192aSMauro Carvalho Chehab 
7752ada815fSHans Verkuil /*
7762ada815fSHans Verkuil  * move buffer to hardware queue
7772ada815fSHans Verkuil  */
saa7134_vb2_buffer_queue(struct vb2_buffer * vb)7782ada815fSHans Verkuil void saa7134_vb2_buffer_queue(struct vb2_buffer *vb)
779b285192aSMauro Carvalho Chehab {
7802ada815fSHans Verkuil 	struct saa7134_dmaqueue *dmaq = vb->vb2_queue->drv_priv;
781a00e6888SHans Verkuil 	struct saa7134_dev *dev = dmaq->dev;
7822d700715SJunghak Sung 	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
7832d700715SJunghak Sung 	struct saa7134_buf *buf = container_of(vbuf, struct saa7134_buf, vb2);
784b285192aSMauro Carvalho Chehab 
7852ada815fSHans Verkuil 	saa7134_buffer_queue(dev, dmaq, buf);
786b285192aSMauro Carvalho Chehab }
7872ada815fSHans Verkuil EXPORT_SYMBOL_GPL(saa7134_vb2_buffer_queue);
788b285192aSMauro Carvalho Chehab 
saa7134_vb2_start_streaming(struct vb2_queue * vq,unsigned int count)7892ada815fSHans Verkuil int saa7134_vb2_start_streaming(struct vb2_queue *vq, unsigned int count)
790b285192aSMauro Carvalho Chehab {
7912ada815fSHans Verkuil 	struct saa7134_dmaqueue *dmaq = vq->drv_priv;
7922ada815fSHans Verkuil 	struct saa7134_dev *dev = dmaq->dev;
793b285192aSMauro Carvalho Chehab 
7942ada815fSHans Verkuil 	/*
7952ada815fSHans Verkuil 	 * Planar video capture and TS share the same DMA channel,
7962ada815fSHans Verkuil 	 * so only one can be active at a time.
7972ada815fSHans Verkuil 	 */
7982ada815fSHans Verkuil 	if (card_is_empress(dev) && vb2_is_busy(&dev->empress_vbq) &&
7992ada815fSHans Verkuil 	    dmaq == &dev->video_q && dev->fmt->planar) {
8002ada815fSHans Verkuil 		struct saa7134_buf *buf, *tmp;
8012ada815fSHans Verkuil 
8022ada815fSHans Verkuil 		list_for_each_entry_safe(buf, tmp, &dmaq->queue, entry) {
8032ada815fSHans Verkuil 			list_del(&buf->entry);
8042d700715SJunghak Sung 			vb2_buffer_done(&buf->vb2.vb2_buf,
8052d700715SJunghak Sung 					VB2_BUF_STATE_QUEUED);
8062ada815fSHans Verkuil 		}
8072ada815fSHans Verkuil 		if (dmaq->curr) {
8082d700715SJunghak Sung 			vb2_buffer_done(&dmaq->curr->vb2.vb2_buf,
8092d700715SJunghak Sung 					VB2_BUF_STATE_QUEUED);
8102ada815fSHans Verkuil 			dmaq->curr = NULL;
8112ada815fSHans Verkuil 		}
8122ada815fSHans Verkuil 		return -EBUSY;
813b285192aSMauro Carvalho Chehab 	}
814b285192aSMauro Carvalho Chehab 
8152ada815fSHans Verkuil 	/* The SAA7134 has a 1K FIFO; the datasheet suggests that when
8162ada815fSHans Verkuil 	 * configured conservatively, there's 22 usec of buffering for video.
8172ada815fSHans Verkuil 	 * We therefore request a DMA latency of 20 usec, giving us 2 usec of
8182ada815fSHans Verkuil 	 * margin in case the FIFO is configured differently to the datasheet.
8192ada815fSHans Verkuil 	 * Unfortunately, I lack register-level documentation to check the
8202ada815fSHans Verkuil 	 * Linux FIFO setup and confirm the perfect value.
8212ada815fSHans Verkuil 	 */
8222ada815fSHans Verkuil 	if ((dmaq == &dev->video_q && !vb2_is_streaming(&dev->vbi_vbq)) ||
8232ada815fSHans Verkuil 	    (dmaq == &dev->vbi_q && !vb2_is_streaming(&dev->video_vbq)))
8247c51a06bSRafael J. Wysocki 		cpu_latency_qos_add_request(&dev->qos_request, 20);
8252ada815fSHans Verkuil 	dmaq->seq_nr = 0;
8262ada815fSHans Verkuil 
8272ada815fSHans Verkuil 	return 0;
8282ada815fSHans Verkuil }
8292ada815fSHans Verkuil 
saa7134_vb2_stop_streaming(struct vb2_queue * vq)8302ada815fSHans Verkuil void saa7134_vb2_stop_streaming(struct vb2_queue *vq)
8312ada815fSHans Verkuil {
8322ada815fSHans Verkuil 	struct saa7134_dmaqueue *dmaq = vq->drv_priv;
8332ada815fSHans Verkuil 	struct saa7134_dev *dev = dmaq->dev;
8342ada815fSHans Verkuil 
8352ada815fSHans Verkuil 	saa7134_stop_streaming(dev, dmaq);
8362ada815fSHans Verkuil 
8372ada815fSHans Verkuil 	if ((dmaq == &dev->video_q && !vb2_is_streaming(&dev->vbi_vbq)) ||
8382ada815fSHans Verkuil 	    (dmaq == &dev->vbi_q && !vb2_is_streaming(&dev->video_vbq)))
8397c51a06bSRafael J. Wysocki 		cpu_latency_qos_remove_request(&dev->qos_request);
8402ada815fSHans Verkuil }
8412ada815fSHans Verkuil 
84210accd2eSJulia Lawall static const struct vb2_ops vb2_qops = {
8432ada815fSHans Verkuil 	.queue_setup	= queue_setup,
8442ada815fSHans Verkuil 	.buf_init	= buffer_init,
845b285192aSMauro Carvalho Chehab 	.buf_prepare	= buffer_prepare,
8462ada815fSHans Verkuil 	.buf_queue	= saa7134_vb2_buffer_queue,
8472ada815fSHans Verkuil 	.wait_prepare	= vb2_ops_wait_prepare,
8482ada815fSHans Verkuil 	.wait_finish	= vb2_ops_wait_finish,
8492ada815fSHans Verkuil 	.start_streaming = saa7134_vb2_start_streaming,
8502ada815fSHans Verkuil 	.stop_streaming = saa7134_vb2_stop_streaming,
851b285192aSMauro Carvalho Chehab };
852b285192aSMauro Carvalho Chehab 
853b285192aSMauro Carvalho Chehab /* ------------------------------------------------------------------ */
854b285192aSMauro Carvalho Chehab 
saa7134_s_ctrl(struct v4l2_ctrl * ctrl)855718bde1aSHans Verkuil static int saa7134_s_ctrl(struct v4l2_ctrl *ctrl)
856b285192aSMauro Carvalho Chehab {
857718bde1aSHans Verkuil 	struct saa7134_dev *dev = container_of(ctrl->handler, struct saa7134_dev, ctrl_handler);
858b285192aSMauro Carvalho Chehab 
859718bde1aSHans Verkuil 	switch (ctrl->id) {
860b285192aSMauro Carvalho Chehab 	case V4L2_CID_BRIGHTNESS:
861718bde1aSHans Verkuil 		dev->ctl_bright = ctrl->val;
862718bde1aSHans Verkuil 		saa_writeb(SAA7134_DEC_LUMA_BRIGHT, ctrl->val);
863b285192aSMauro Carvalho Chehab 		break;
864b285192aSMauro Carvalho Chehab 	case V4L2_CID_HUE:
865718bde1aSHans Verkuil 		dev->ctl_hue = ctrl->val;
866718bde1aSHans Verkuil 		saa_writeb(SAA7134_DEC_CHROMA_HUE, ctrl->val);
867b285192aSMauro Carvalho Chehab 		break;
868b285192aSMauro Carvalho Chehab 	case V4L2_CID_CONTRAST:
869718bde1aSHans Verkuil 		dev->ctl_contrast = ctrl->val;
870b285192aSMauro Carvalho Chehab 		saa_writeb(SAA7134_DEC_LUMA_CONTRAST,
871b285192aSMauro Carvalho Chehab 			   dev->ctl_invert ? -dev->ctl_contrast : dev->ctl_contrast);
872b285192aSMauro Carvalho Chehab 		break;
873b285192aSMauro Carvalho Chehab 	case V4L2_CID_SATURATION:
874718bde1aSHans Verkuil 		dev->ctl_saturation = ctrl->val;
875b285192aSMauro Carvalho Chehab 		saa_writeb(SAA7134_DEC_CHROMA_SATURATION,
876b285192aSMauro Carvalho Chehab 			   dev->ctl_invert ? -dev->ctl_saturation : dev->ctl_saturation);
877b285192aSMauro Carvalho Chehab 		break;
878b285192aSMauro Carvalho Chehab 	case V4L2_CID_AUDIO_MUTE:
879718bde1aSHans Verkuil 		dev->ctl_mute = ctrl->val;
880b285192aSMauro Carvalho Chehab 		saa7134_tvaudio_setmute(dev);
881b285192aSMauro Carvalho Chehab 		break;
882b285192aSMauro Carvalho Chehab 	case V4L2_CID_AUDIO_VOLUME:
883718bde1aSHans Verkuil 		dev->ctl_volume = ctrl->val;
884b285192aSMauro Carvalho Chehab 		saa7134_tvaudio_setvolume(dev,dev->ctl_volume);
885b285192aSMauro Carvalho Chehab 		break;
886b285192aSMauro Carvalho Chehab 	case V4L2_CID_PRIVATE_INVERT:
887718bde1aSHans Verkuil 		dev->ctl_invert = ctrl->val;
888b285192aSMauro Carvalho Chehab 		saa_writeb(SAA7134_DEC_LUMA_CONTRAST,
889b285192aSMauro Carvalho Chehab 			   dev->ctl_invert ? -dev->ctl_contrast : dev->ctl_contrast);
890b285192aSMauro Carvalho Chehab 		saa_writeb(SAA7134_DEC_CHROMA_SATURATION,
891b285192aSMauro Carvalho Chehab 			   dev->ctl_invert ? -dev->ctl_saturation : dev->ctl_saturation);
892b285192aSMauro Carvalho Chehab 		break;
893b285192aSMauro Carvalho Chehab 	case V4L2_CID_HFLIP:
894718bde1aSHans Verkuil 		dev->ctl_mirror = ctrl->val;
895b285192aSMauro Carvalho Chehab 		break;
896b285192aSMauro Carvalho Chehab 	case V4L2_CID_PRIVATE_Y_EVEN:
897718bde1aSHans Verkuil 		dev->ctl_y_even = ctrl->val;
898b285192aSMauro Carvalho Chehab 		break;
899b285192aSMauro Carvalho Chehab 	case V4L2_CID_PRIVATE_Y_ODD:
900718bde1aSHans Verkuil 		dev->ctl_y_odd = ctrl->val;
901b285192aSMauro Carvalho Chehab 		break;
902b285192aSMauro Carvalho Chehab 	case V4L2_CID_PRIVATE_AUTOMUTE:
903b285192aSMauro Carvalho Chehab 	{
904b285192aSMauro Carvalho Chehab 		struct v4l2_priv_tun_config tda9887_cfg;
905b285192aSMauro Carvalho Chehab 
906b285192aSMauro Carvalho Chehab 		tda9887_cfg.tuner = TUNER_TDA9887;
907b285192aSMauro Carvalho Chehab 		tda9887_cfg.priv = &dev->tda9887_conf;
908b285192aSMauro Carvalho Chehab 
909718bde1aSHans Verkuil 		dev->ctl_automute = ctrl->val;
910b285192aSMauro Carvalho Chehab 		if (dev->tda9887_conf) {
911b285192aSMauro Carvalho Chehab 			if (dev->ctl_automute)
912b285192aSMauro Carvalho Chehab 				dev->tda9887_conf |= TDA9887_AUTOMUTE;
913b285192aSMauro Carvalho Chehab 			else
914b285192aSMauro Carvalho Chehab 				dev->tda9887_conf &= ~TDA9887_AUTOMUTE;
915b285192aSMauro Carvalho Chehab 
916b285192aSMauro Carvalho Chehab 			saa_call_all(dev, tuner, s_config, &tda9887_cfg);
917b285192aSMauro Carvalho Chehab 		}
918b285192aSMauro Carvalho Chehab 		break;
919b285192aSMauro Carvalho Chehab 	}
920b285192aSMauro Carvalho Chehab 	default:
921718bde1aSHans Verkuil 		return -EINVAL;
922b285192aSMauro Carvalho Chehab 	}
923718bde1aSHans Verkuil 	return 0;
924b285192aSMauro Carvalho Chehab }
925b285192aSMauro Carvalho Chehab 
926b285192aSMauro Carvalho Chehab /* ------------------------------------------------------------------ */
927b285192aSMauro Carvalho Chehab 
video_open(struct file * file)928b285192aSMauro Carvalho Chehab static int video_open(struct file *file)
929b285192aSMauro Carvalho Chehab {
930b285192aSMauro Carvalho Chehab 	struct video_device *vdev = video_devdata(file);
931b285192aSMauro Carvalho Chehab 	struct saa7134_dev *dev = video_drvdata(file);
9322ada815fSHans Verkuil 	int ret = v4l2_fh_open(file);
933b285192aSMauro Carvalho Chehab 
9342ada815fSHans Verkuil 	if (ret < 0)
9352ada815fSHans Verkuil 		return ret;
936b285192aSMauro Carvalho Chehab 
9372ada815fSHans Verkuil 	mutex_lock(&dev->lock);
9388fcd4769SHans Verkuil 	if (vdev->vfl_type == VFL_TYPE_RADIO) {
939b285192aSMauro Carvalho Chehab 		/* switch to radio mode */
940b285192aSMauro Carvalho Chehab 		saa7134_tvaudio_setinput(dev, &card(dev).radio);
941b285192aSMauro Carvalho Chehab 		saa_call_all(dev, tuner, s_radio);
942b285192aSMauro Carvalho Chehab 	} else {
943b285192aSMauro Carvalho Chehab 		/* switch to video/vbi mode */
944b285192aSMauro Carvalho Chehab 		video_mux(dev, dev->ctl_input);
945b285192aSMauro Carvalho Chehab 	}
9462ada815fSHans Verkuil 	mutex_unlock(&dev->lock);
9473bbaa3a6SOndrej Zary 
948b285192aSMauro Carvalho Chehab 	return 0;
949b285192aSMauro Carvalho Chehab }
950b285192aSMauro Carvalho Chehab 
video_release(struct file * file)951b285192aSMauro Carvalho Chehab static int video_release(struct file *file)
952b285192aSMauro Carvalho Chehab {
9538fcd4769SHans Verkuil 	struct video_device *vdev = video_devdata(file);
954b9f63b25SHans Verkuil 	struct saa7134_dev *dev = video_drvdata(file);
955b285192aSMauro Carvalho Chehab 	struct saa6588_command cmd;
956b285192aSMauro Carvalho Chehab 
9572ada815fSHans Verkuil 	mutex_lock(&dev->lock);
958b285192aSMauro Carvalho Chehab 	saa7134_tvaudio_close(dev);
959b285192aSMauro Carvalho Chehab 
9602ada815fSHans Verkuil 	if (vdev->vfl_type == VFL_TYPE_RADIO)
9612ada815fSHans Verkuil 		v4l2_fh_release(file);
9622ada815fSHans Verkuil 	else
9632ada815fSHans Verkuil 		_vb2_fop_release(file, NULL);
964b285192aSMauro Carvalho Chehab 
965b285192aSMauro Carvalho Chehab 	/* ts-capture will not work in planar mode, so turn it off Hac: 04.05*/
966b285192aSMauro Carvalho Chehab 	saa_andorb(SAA7134_OFMT_VIDEO_A, 0x1f, 0);
967b285192aSMauro Carvalho Chehab 	saa_andorb(SAA7134_OFMT_VIDEO_B, 0x1f, 0);
968b285192aSMauro Carvalho Chehab 	saa_andorb(SAA7134_OFMT_DATA_A, 0x1f, 0);
969b285192aSMauro Carvalho Chehab 	saa_andorb(SAA7134_OFMT_DATA_B, 0x1f, 0);
970b285192aSMauro Carvalho Chehab 
9713aab15afSHans Verkuil 	saa_call_all(dev, tuner, standby);
9728fcd4769SHans Verkuil 	if (vdev->vfl_type == VFL_TYPE_RADIO)
9730a7790beSArnd Bergmann 		saa_call_all(dev, core, command, SAA6588_CMD_CLOSE, &cmd);
9742ada815fSHans Verkuil 	mutex_unlock(&dev->lock);
975b285192aSMauro Carvalho Chehab 
976b285192aSMauro Carvalho Chehab 	return 0;
977b285192aSMauro Carvalho Chehab }
978b285192aSMauro Carvalho Chehab 
radio_read(struct file * file,char __user * data,size_t count,loff_t * ppos)979b285192aSMauro Carvalho Chehab static ssize_t radio_read(struct file *file, char __user *data,
980b285192aSMauro Carvalho Chehab 			 size_t count, loff_t *ppos)
981b285192aSMauro Carvalho Chehab {
982b9f63b25SHans Verkuil 	struct saa7134_dev *dev = video_drvdata(file);
983b285192aSMauro Carvalho Chehab 	struct saa6588_command cmd;
984b285192aSMauro Carvalho Chehab 
985b285192aSMauro Carvalho Chehab 	cmd.block_count = count/3;
98609092787SHans Verkuil 	cmd.nonblocking = file->f_flags & O_NONBLOCK;
987b285192aSMauro Carvalho Chehab 	cmd.buffer = data;
988b285192aSMauro Carvalho Chehab 	cmd.instance = file;
989b285192aSMauro Carvalho Chehab 	cmd.result = -ENODEV;
990b285192aSMauro Carvalho Chehab 
9912ada815fSHans Verkuil 	mutex_lock(&dev->lock);
9920a7790beSArnd Bergmann 	saa_call_all(dev, core, command, SAA6588_CMD_READ, &cmd);
9932ada815fSHans Verkuil 	mutex_unlock(&dev->lock);
994b285192aSMauro Carvalho Chehab 
995b285192aSMauro Carvalho Chehab 	return cmd.result;
996b285192aSMauro Carvalho Chehab }
997b285192aSMauro Carvalho Chehab 
radio_poll(struct file * file,poll_table * wait)998c23e0cb8SAl Viro static __poll_t radio_poll(struct file *file, poll_table *wait)
999b285192aSMauro Carvalho Chehab {
1000b9f63b25SHans Verkuil 	struct saa7134_dev *dev = video_drvdata(file);
1001b285192aSMauro Carvalho Chehab 	struct saa6588_command cmd;
1002c23e0cb8SAl Viro 	__poll_t rc = v4l2_ctrl_poll(file, wait);
1003b285192aSMauro Carvalho Chehab 
1004b285192aSMauro Carvalho Chehab 	cmd.instance = file;
1005b285192aSMauro Carvalho Chehab 	cmd.event_list = wait;
100637b3c6a6SAl Viro 	cmd.poll_mask = 0;
10072ada815fSHans Verkuil 	mutex_lock(&dev->lock);
10080a7790beSArnd Bergmann 	saa_call_all(dev, core, command, SAA6588_CMD_POLL, &cmd);
10092ada815fSHans Verkuil 	mutex_unlock(&dev->lock);
1010b285192aSMauro Carvalho Chehab 
101137b3c6a6SAl Viro 	return rc | cmd.poll_mask;
1012b285192aSMauro Carvalho Chehab }
1013b285192aSMauro Carvalho Chehab 
1014b285192aSMauro Carvalho Chehab /* ------------------------------------------------------------------ */
1015b285192aSMauro Carvalho Chehab 
saa7134_try_get_set_fmt_vbi_cap(struct file * file,void * priv,struct v4l2_format * f)1016b285192aSMauro Carvalho Chehab static int saa7134_try_get_set_fmt_vbi_cap(struct file *file, void *priv,
1017b285192aSMauro Carvalho Chehab 						struct v4l2_format *f)
1018b285192aSMauro Carvalho Chehab {
1019b9f63b25SHans Verkuil 	struct saa7134_dev *dev = video_drvdata(file);
1020b285192aSMauro Carvalho Chehab 	struct saa7134_tvnorm *norm = dev->tvnorm;
1021b285192aSMauro Carvalho Chehab 
1022d047795cSOndrej Zary 	memset(&f->fmt.vbi.reserved, 0, sizeof(f->fmt.vbi.reserved));
1023b285192aSMauro Carvalho Chehab 	f->fmt.vbi.sampling_rate = 6750000 * 4;
1024b285192aSMauro Carvalho Chehab 	f->fmt.vbi.samples_per_line = 2048 /* VBI_LINE_LENGTH */;
1025b285192aSMauro Carvalho Chehab 	f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
1026b285192aSMauro Carvalho Chehab 	f->fmt.vbi.offset = 64 * 4;
1027b285192aSMauro Carvalho Chehab 	f->fmt.vbi.start[0] = norm->vbi_v_start_0;
1028b285192aSMauro Carvalho Chehab 	f->fmt.vbi.count[0] = norm->vbi_v_stop_0 - norm->vbi_v_start_0 +1;
1029b285192aSMauro Carvalho Chehab 	f->fmt.vbi.start[1] = norm->vbi_v_start_1;
1030b285192aSMauro Carvalho Chehab 	f->fmt.vbi.count[1] = f->fmt.vbi.count[0];
1031b285192aSMauro Carvalho Chehab 	f->fmt.vbi.flags = 0; /* VBI_UNSYNC VBI_INTERLACED */
1032b285192aSMauro Carvalho Chehab 
1033b285192aSMauro Carvalho Chehab 	return 0;
1034b285192aSMauro Carvalho Chehab }
1035b285192aSMauro Carvalho Chehab 
saa7134_g_fmt_vid_cap(struct file * file,void * priv,struct v4l2_format * f)1036b285192aSMauro Carvalho Chehab static int saa7134_g_fmt_vid_cap(struct file *file, void *priv,
1037b285192aSMauro Carvalho Chehab 				struct v4l2_format *f)
1038b285192aSMauro Carvalho Chehab {
1039b9f63b25SHans Verkuil 	struct saa7134_dev *dev = video_drvdata(file);
1040b285192aSMauro Carvalho Chehab 
1041813b9dffSHans Verkuil 	f->fmt.pix.width        = dev->width;
1042813b9dffSHans Verkuil 	f->fmt.pix.height       = dev->height;
10432ada815fSHans Verkuil 	f->fmt.pix.field        = dev->field;
1044813b9dffSHans Verkuil 	f->fmt.pix.pixelformat  = dev->fmt->fourcc;
10453e71da19SHans de Goede 	if (dev->fmt->planar)
10463e71da19SHans de Goede 		f->fmt.pix.bytesperline = f->fmt.pix.width;
10473e71da19SHans de Goede 	else
1048b285192aSMauro Carvalho Chehab 		f->fmt.pix.bytesperline =
10493e71da19SHans de Goede 			(f->fmt.pix.width * dev->fmt->depth) / 8;
1050b285192aSMauro Carvalho Chehab 	f->fmt.pix.sizeimage =
10513e71da19SHans de Goede 		(f->fmt.pix.height * f->fmt.pix.width * dev->fmt->depth) / 8;
10523a0a5a78SHans Verkuil 	f->fmt.pix.colorspace   = V4L2_COLORSPACE_SMPTE170M;
1053b285192aSMauro Carvalho Chehab 	return 0;
1054b285192aSMauro Carvalho Chehab }
1055b285192aSMauro Carvalho Chehab 
saa7134_try_fmt_vid_cap(struct file * file,void * priv,struct v4l2_format * f)1056b285192aSMauro Carvalho Chehab static int saa7134_try_fmt_vid_cap(struct file *file, void *priv,
1057b285192aSMauro Carvalho Chehab 						struct v4l2_format *f)
1058b285192aSMauro Carvalho Chehab {
1059b9f63b25SHans Verkuil 	struct saa7134_dev *dev = video_drvdata(file);
1060b285192aSMauro Carvalho Chehab 	struct saa7134_format *fmt;
1061b285192aSMauro Carvalho Chehab 	enum v4l2_field field;
1062b285192aSMauro Carvalho Chehab 	unsigned int maxw, maxh;
1063b285192aSMauro Carvalho Chehab 
1064b285192aSMauro Carvalho Chehab 	fmt = format_by_fourcc(f->fmt.pix.pixelformat);
1065b285192aSMauro Carvalho Chehab 	if (NULL == fmt)
1066b285192aSMauro Carvalho Chehab 		return -EINVAL;
1067b285192aSMauro Carvalho Chehab 
1068b285192aSMauro Carvalho Chehab 	field = f->fmt.pix.field;
1069b285192aSMauro Carvalho Chehab 	maxw  = min(dev->crop_current.width*4,  dev->crop_bounds.width);
1070b285192aSMauro Carvalho Chehab 	maxh  = min(dev->crop_current.height*4, dev->crop_bounds.height);
1071b285192aSMauro Carvalho Chehab 
1072b285192aSMauro Carvalho Chehab 	if (V4L2_FIELD_ANY == field) {
1073b285192aSMauro Carvalho Chehab 		field = (f->fmt.pix.height > maxh/2)
1074b285192aSMauro Carvalho Chehab 			? V4L2_FIELD_INTERLACED
1075b285192aSMauro Carvalho Chehab 			: V4L2_FIELD_BOTTOM;
1076b285192aSMauro Carvalho Chehab 	}
1077b285192aSMauro Carvalho Chehab 	switch (field) {
1078b285192aSMauro Carvalho Chehab 	case V4L2_FIELD_TOP:
1079b285192aSMauro Carvalho Chehab 	case V4L2_FIELD_BOTTOM:
1080b285192aSMauro Carvalho Chehab 		maxh = maxh / 2;
1081b285192aSMauro Carvalho Chehab 		break;
1082b285192aSMauro Carvalho Chehab 	default:
10833a0a5a78SHans Verkuil 		field = V4L2_FIELD_INTERLACED;
10843a0a5a78SHans Verkuil 		break;
1085b285192aSMauro Carvalho Chehab 	}
1086b285192aSMauro Carvalho Chehab 
1087b285192aSMauro Carvalho Chehab 	f->fmt.pix.field = field;
1088b285192aSMauro Carvalho Chehab 	if (f->fmt.pix.width  < 48)
1089b285192aSMauro Carvalho Chehab 		f->fmt.pix.width  = 48;
1090b285192aSMauro Carvalho Chehab 	if (f->fmt.pix.height < 32)
1091b285192aSMauro Carvalho Chehab 		f->fmt.pix.height = 32;
1092b285192aSMauro Carvalho Chehab 	if (f->fmt.pix.width > maxw)
1093b285192aSMauro Carvalho Chehab 		f->fmt.pix.width = maxw;
1094b285192aSMauro Carvalho Chehab 	if (f->fmt.pix.height > maxh)
1095b285192aSMauro Carvalho Chehab 		f->fmt.pix.height = maxh;
1096b285192aSMauro Carvalho Chehab 	f->fmt.pix.width &= ~0x03;
10973e71da19SHans de Goede 	if (fmt->planar)
10983e71da19SHans de Goede 		f->fmt.pix.bytesperline = f->fmt.pix.width;
10993e71da19SHans de Goede 	else
1100b285192aSMauro Carvalho Chehab 		f->fmt.pix.bytesperline =
11013e71da19SHans de Goede 			(f->fmt.pix.width * fmt->depth) / 8;
1102b285192aSMauro Carvalho Chehab 	f->fmt.pix.sizeimage =
11033e71da19SHans de Goede 		(f->fmt.pix.height * f->fmt.pix.width * fmt->depth) / 8;
11043a0a5a78SHans Verkuil 	f->fmt.pix.colorspace   = V4L2_COLORSPACE_SMPTE170M;
1105b285192aSMauro Carvalho Chehab 
1106b285192aSMauro Carvalho Chehab 	return 0;
1107b285192aSMauro Carvalho Chehab }
1108b285192aSMauro Carvalho Chehab 
saa7134_s_fmt_vid_cap(struct file * file,void * priv,struct v4l2_format * f)1109b285192aSMauro Carvalho Chehab static int saa7134_s_fmt_vid_cap(struct file *file, void *priv,
1110b285192aSMauro Carvalho Chehab 					struct v4l2_format *f)
1111b285192aSMauro Carvalho Chehab {
1112b9f63b25SHans Verkuil 	struct saa7134_dev *dev = video_drvdata(file);
1113b285192aSMauro Carvalho Chehab 	int err;
1114b285192aSMauro Carvalho Chehab 
1115b285192aSMauro Carvalho Chehab 	err = saa7134_try_fmt_vid_cap(file, priv, f);
1116b285192aSMauro Carvalho Chehab 	if (0 != err)
1117b285192aSMauro Carvalho Chehab 		return err;
1118b285192aSMauro Carvalho Chehab 
1119813b9dffSHans Verkuil 	dev->fmt = format_by_fourcc(f->fmt.pix.pixelformat);
1120813b9dffSHans Verkuil 	dev->width = f->fmt.pix.width;
1121813b9dffSHans Verkuil 	dev->height = f->fmt.pix.height;
11222ada815fSHans Verkuil 	dev->field = f->fmt.pix.field;
1123b285192aSMauro Carvalho Chehab 	return 0;
1124b285192aSMauro Carvalho Chehab }
1125b285192aSMauro Carvalho Chehab 
saa7134_enum_input(struct file * file,void * priv,struct v4l2_input * i)1126b93a18d5SHans Verkuil int saa7134_enum_input(struct file *file, void *priv, struct v4l2_input *i)
1127b285192aSMauro Carvalho Chehab {
1128b93a18d5SHans Verkuil 	struct saa7134_dev *dev = video_drvdata(file);
1129b285192aSMauro Carvalho Chehab 	unsigned int n;
1130b285192aSMauro Carvalho Chehab 
1131b285192aSMauro Carvalho Chehab 	n = i->index;
1132b285192aSMauro Carvalho Chehab 	if (n >= SAA7134_INPUT_MAX)
1133b285192aSMauro Carvalho Chehab 		return -EINVAL;
11348fc34867SMauro Carvalho Chehab 	if (card_in(dev, i->index).type == SAA7134_NO_INPUT)
1135b285192aSMauro Carvalho Chehab 		return -EINVAL;
1136b285192aSMauro Carvalho Chehab 	i->index = n;
1137cc1e6315SMauro Carvalho Chehab 	strscpy(i->name, saa7134_input_name[card_in(dev, n).type],
1138cc1e6315SMauro Carvalho Chehab 		sizeof(i->name));
11398bf77f9eSMauro Carvalho Chehab 	switch (card_in(dev, n).type) {
11408bf77f9eSMauro Carvalho Chehab 	case SAA7134_INPUT_TV:
11418bf77f9eSMauro Carvalho Chehab 	case SAA7134_INPUT_TV_MONO:
1142b285192aSMauro Carvalho Chehab 		i->type = V4L2_INPUT_TYPE_TUNER;
11438bf77f9eSMauro Carvalho Chehab 		break;
11448bf77f9eSMauro Carvalho Chehab 	default:
11458bf77f9eSMauro Carvalho Chehab 		i->type  = V4L2_INPUT_TYPE_CAMERA;
11468bf77f9eSMauro Carvalho Chehab 		break;
11478bf77f9eSMauro Carvalho Chehab 	}
1148b285192aSMauro Carvalho Chehab 	if (n == dev->ctl_input) {
1149b285192aSMauro Carvalho Chehab 		int v1 = saa_readb(SAA7134_STATUS_VIDEO1);
1150b285192aSMauro Carvalho Chehab 		int v2 = saa_readb(SAA7134_STATUS_VIDEO2);
1151b285192aSMauro Carvalho Chehab 
1152b285192aSMauro Carvalho Chehab 		if (0 != (v1 & 0x40))
1153b285192aSMauro Carvalho Chehab 			i->status |= V4L2_IN_ST_NO_H_LOCK;
1154b285192aSMauro Carvalho Chehab 		if (0 != (v2 & 0x40))
115595075dd0SHans Verkuil 			i->status |= V4L2_IN_ST_NO_SIGNAL;
1156b285192aSMauro Carvalho Chehab 		if (0 != (v2 & 0x0e))
1157b285192aSMauro Carvalho Chehab 			i->status |= V4L2_IN_ST_MACROVISION;
1158b285192aSMauro Carvalho Chehab 	}
1159b285192aSMauro Carvalho Chehab 	i->std = SAA7134_NORMS;
1160b285192aSMauro Carvalho Chehab 	return 0;
1161b285192aSMauro Carvalho Chehab }
1162b93a18d5SHans Verkuil EXPORT_SYMBOL_GPL(saa7134_enum_input);
1163b285192aSMauro Carvalho Chehab 
saa7134_g_input(struct file * file,void * priv,unsigned int * i)1164b93a18d5SHans Verkuil int saa7134_g_input(struct file *file, void *priv, unsigned int *i)
1165b285192aSMauro Carvalho Chehab {
1166b93a18d5SHans Verkuil 	struct saa7134_dev *dev = video_drvdata(file);
1167b285192aSMauro Carvalho Chehab 
1168b285192aSMauro Carvalho Chehab 	*i = dev->ctl_input;
1169b285192aSMauro Carvalho Chehab 	return 0;
1170b285192aSMauro Carvalho Chehab }
1171b93a18d5SHans Verkuil EXPORT_SYMBOL_GPL(saa7134_g_input);
1172b285192aSMauro Carvalho Chehab 
saa7134_s_input(struct file * file,void * priv,unsigned int i)1173b93a18d5SHans Verkuil int saa7134_s_input(struct file *file, void *priv, unsigned int i)
1174b285192aSMauro Carvalho Chehab {
1175b93a18d5SHans Verkuil 	struct saa7134_dev *dev = video_drvdata(file);
1176b285192aSMauro Carvalho Chehab 
1177b285192aSMauro Carvalho Chehab 	if (i >= SAA7134_INPUT_MAX)
1178b285192aSMauro Carvalho Chehab 		return -EINVAL;
11798fc34867SMauro Carvalho Chehab 	if (card_in(dev, i).type == SAA7134_NO_INPUT)
1180b285192aSMauro Carvalho Chehab 		return -EINVAL;
1181b285192aSMauro Carvalho Chehab 	video_mux(dev, i);
1182b285192aSMauro Carvalho Chehab 	return 0;
1183b285192aSMauro Carvalho Chehab }
1184b93a18d5SHans Verkuil EXPORT_SYMBOL_GPL(saa7134_s_input);
1185b285192aSMauro Carvalho Chehab 
saa7134_querycap(struct file * file,void * priv,struct v4l2_capability * cap)1186b93a18d5SHans Verkuil int saa7134_querycap(struct file *file, void *priv,
1187b285192aSMauro Carvalho Chehab 					struct v4l2_capability *cap)
1188b285192aSMauro Carvalho Chehab {
1189b93a18d5SHans Verkuil 	struct saa7134_dev *dev = video_drvdata(file);
1190b285192aSMauro Carvalho Chehab 
1191cc1e6315SMauro Carvalho Chehab 	strscpy(cap->driver, "saa7134", sizeof(cap->driver));
1192c0decac1SMauro Carvalho Chehab 	strscpy(cap->card, saa7134_boards[dev->board].name,
1193b285192aSMauro Carvalho Chehab 		sizeof(cap->card));
119421615365SHans Verkuil 	cap->capabilities = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING |
119521615365SHans Verkuil 			    V4L2_CAP_RADIO | V4L2_CAP_VIDEO_CAPTURE |
119621615365SHans Verkuil 			    V4L2_CAP_VBI_CAPTURE | V4L2_CAP_DEVICE_CAPS;
119721615365SHans Verkuil 	if (dev->tuner_type != TUNER_ABSENT && dev->tuner_type != UNSET)
119821615365SHans Verkuil 		cap->capabilities |= V4L2_CAP_TUNER;
1199c3b3e0c5SOndrej Zary 	if (dev->has_rds)
120021615365SHans Verkuil 		cap->capabilities |= V4L2_CAP_RDS_CAPTURE;
1201c3b3e0c5SOndrej Zary 
1202b285192aSMauro Carvalho Chehab 	return 0;
1203b285192aSMauro Carvalho Chehab }
1204b93a18d5SHans Verkuil EXPORT_SYMBOL_GPL(saa7134_querycap);
1205b285192aSMauro Carvalho Chehab 
saa7134_s_std(struct file * file,void * priv,v4l2_std_id id)1206b93a18d5SHans Verkuil int saa7134_s_std(struct file *file, void *priv, v4l2_std_id id)
1207b285192aSMauro Carvalho Chehab {
1208b93a18d5SHans Verkuil 	struct saa7134_dev *dev = video_drvdata(file);
1209b285192aSMauro Carvalho Chehab 	unsigned int i;
1210b285192aSMauro Carvalho Chehab 	v4l2_std_id fixup;
1211b285192aSMauro Carvalho Chehab 
1212b285192aSMauro Carvalho Chehab 	for (i = 0; i < TVNORMS; i++)
1213314527acSHans Verkuil 		if (id == tvnorms[i].id)
1214b285192aSMauro Carvalho Chehab 			break;
1215b285192aSMauro Carvalho Chehab 
1216b285192aSMauro Carvalho Chehab 	if (i == TVNORMS)
1217b285192aSMauro Carvalho Chehab 		for (i = 0; i < TVNORMS; i++)
1218314527acSHans Verkuil 			if (id & tvnorms[i].id)
1219b285192aSMauro Carvalho Chehab 				break;
1220b285192aSMauro Carvalho Chehab 	if (i == TVNORMS)
1221b285192aSMauro Carvalho Chehab 		return -EINVAL;
1222b285192aSMauro Carvalho Chehab 
1223314527acSHans Verkuil 	if ((id & V4L2_STD_SECAM) && (secam[0] != '-')) {
1224b285192aSMauro Carvalho Chehab 		if (secam[0] == 'L' || secam[0] == 'l') {
1225b285192aSMauro Carvalho Chehab 			if (secam[1] == 'C' || secam[1] == 'c')
1226b285192aSMauro Carvalho Chehab 				fixup = V4L2_STD_SECAM_LC;
1227b285192aSMauro Carvalho Chehab 			else
1228b285192aSMauro Carvalho Chehab 				fixup = V4L2_STD_SECAM_L;
1229b285192aSMauro Carvalho Chehab 		} else {
1230b285192aSMauro Carvalho Chehab 			if (secam[0] == 'D' || secam[0] == 'd')
1231b285192aSMauro Carvalho Chehab 				fixup = V4L2_STD_SECAM_DK;
1232b285192aSMauro Carvalho Chehab 			else
1233b285192aSMauro Carvalho Chehab 				fixup = V4L2_STD_SECAM;
1234b285192aSMauro Carvalho Chehab 		}
1235b285192aSMauro Carvalho Chehab 		for (i = 0; i < TVNORMS; i++) {
1236b285192aSMauro Carvalho Chehab 			if (fixup == tvnorms[i].id)
1237b285192aSMauro Carvalho Chehab 				break;
1238b285192aSMauro Carvalho Chehab 		}
1239b285192aSMauro Carvalho Chehab 		if (i == TVNORMS)
1240b285192aSMauro Carvalho Chehab 			return -EINVAL;
1241b285192aSMauro Carvalho Chehab 	}
1242b285192aSMauro Carvalho Chehab 
1243b285192aSMauro Carvalho Chehab 	set_tvnorm(dev, &tvnorms[i]);
1244b285192aSMauro Carvalho Chehab 
1245b285192aSMauro Carvalho Chehab 	saa7134_tvaudio_do_scan(dev);
1246b285192aSMauro Carvalho Chehab 	return 0;
1247b285192aSMauro Carvalho Chehab }
1248b93a18d5SHans Verkuil EXPORT_SYMBOL_GPL(saa7134_s_std);
1249b285192aSMauro Carvalho Chehab 
saa7134_g_std(struct file * file,void * priv,v4l2_std_id * id)1250b93a18d5SHans Verkuil int saa7134_g_std(struct file *file, void *priv, v4l2_std_id *id)
1251b285192aSMauro Carvalho Chehab {
1252b93a18d5SHans Verkuil 	struct saa7134_dev *dev = video_drvdata(file);
1253b285192aSMauro Carvalho Chehab 
1254b285192aSMauro Carvalho Chehab 	*id = dev->tvnorm->id;
1255b285192aSMauro Carvalho Chehab 	return 0;
1256b285192aSMauro Carvalho Chehab }
1257b93a18d5SHans Verkuil EXPORT_SYMBOL_GPL(saa7134_g_std);
1258b285192aSMauro Carvalho Chehab 
saa7134_read_std(struct saa7134_dev * dev)1259707b7f80SMikhail Domrachev static v4l2_std_id saa7134_read_std(struct saa7134_dev *dev)
1260707b7f80SMikhail Domrachev {
1261707b7f80SMikhail Domrachev 	static v4l2_std_id stds[] = {
1262707b7f80SMikhail Domrachev 		V4L2_STD_UNKNOWN,
1263707b7f80SMikhail Domrachev 		V4L2_STD_NTSC,
1264707b7f80SMikhail Domrachev 		V4L2_STD_PAL,
1265707b7f80SMikhail Domrachev 		V4L2_STD_SECAM };
1266707b7f80SMikhail Domrachev 
1267707b7f80SMikhail Domrachev 	v4l2_std_id result = 0;
1268707b7f80SMikhail Domrachev 
1269707b7f80SMikhail Domrachev 	u8 st1 = saa_readb(SAA7134_STATUS_VIDEO1);
1270707b7f80SMikhail Domrachev 	u8 st2 = saa_readb(SAA7134_STATUS_VIDEO2);
1271707b7f80SMikhail Domrachev 
1272707b7f80SMikhail Domrachev 	if (!(st2 & 0x1)) /* RDCAP == 0 */
1273707b7f80SMikhail Domrachev 		result = V4L2_STD_UNKNOWN;
1274707b7f80SMikhail Domrachev 	else
1275707b7f80SMikhail Domrachev 		result = stds[st1 & 0x03];
1276707b7f80SMikhail Domrachev 
1277707b7f80SMikhail Domrachev 	return result;
1278707b7f80SMikhail Domrachev }
1279707b7f80SMikhail Domrachev 
saa7134_querystd(struct file * file,void * priv,v4l2_std_id * std)1280707b7f80SMikhail Domrachev int saa7134_querystd(struct file *file, void *priv, v4l2_std_id *std)
1281707b7f80SMikhail Domrachev {
1282707b7f80SMikhail Domrachev 	struct saa7134_dev *dev = video_drvdata(file);
1283707b7f80SMikhail Domrachev 	*std &= saa7134_read_std(dev);
1284707b7f80SMikhail Domrachev 	return 0;
1285707b7f80SMikhail Domrachev }
1286707b7f80SMikhail Domrachev EXPORT_SYMBOL_GPL(saa7134_querystd);
1287707b7f80SMikhail Domrachev 
saa7134_g_pixelaspect(struct file * file,void * priv,int type,struct v4l2_fract * f)12885200ab6aSHans Verkuil static int saa7134_g_pixelaspect(struct file *file, void *priv,
12895200ab6aSHans Verkuil 				 int type, struct v4l2_fract *f)
1290b285192aSMauro Carvalho Chehab {
1291b9f63b25SHans Verkuil 	struct saa7134_dev *dev = video_drvdata(file);
1292b285192aSMauro Carvalho Chehab 
129350a5677dSHans Verkuil 	if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1294b285192aSMauro Carvalho Chehab 		return -EINVAL;
12955200ab6aSHans Verkuil 
1296b285192aSMauro Carvalho Chehab 	if (dev->tvnorm->id & V4L2_STD_525_60) {
12975200ab6aSHans Verkuil 		f->numerator   = 11;
12985200ab6aSHans Verkuil 		f->denominator = 10;
1299b285192aSMauro Carvalho Chehab 	}
1300b285192aSMauro Carvalho Chehab 	if (dev->tvnorm->id & V4L2_STD_625_50) {
13015200ab6aSHans Verkuil 		f->numerator   = 54;
13025200ab6aSHans Verkuil 		f->denominator = 59;
1303b285192aSMauro Carvalho Chehab 	}
1304b285192aSMauro Carvalho Chehab 	return 0;
1305b285192aSMauro Carvalho Chehab }
1306b285192aSMauro Carvalho Chehab 
saa7134_g_selection(struct file * file,void * f,struct v4l2_selection * sel)1307802d62c1SHans Verkuil static int saa7134_g_selection(struct file *file, void *f, struct v4l2_selection *sel)
1308b285192aSMauro Carvalho Chehab {
1309b9f63b25SHans Verkuil 	struct saa7134_dev *dev = video_drvdata(file);
1310b285192aSMauro Carvalho Chehab 
131150a5677dSHans Verkuil 	if (sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1312b285192aSMauro Carvalho Chehab 		return -EINVAL;
1313802d62c1SHans Verkuil 
1314802d62c1SHans Verkuil 	switch (sel->target) {
1315802d62c1SHans Verkuil 	case V4L2_SEL_TGT_CROP:
1316802d62c1SHans Verkuil 		sel->r = dev->crop_current;
1317802d62c1SHans Verkuil 		break;
1318802d62c1SHans Verkuil 	case V4L2_SEL_TGT_CROP_DEFAULT:
1319802d62c1SHans Verkuil 		sel->r = dev->crop_defrect;
1320802d62c1SHans Verkuil 		break;
1321802d62c1SHans Verkuil 	case V4L2_SEL_TGT_CROP_BOUNDS:
1322802d62c1SHans Verkuil 		sel->r  = dev->crop_bounds;
1323802d62c1SHans Verkuil 		break;
1324802d62c1SHans Verkuil 	default:
1325802d62c1SHans Verkuil 		return -EINVAL;
1326802d62c1SHans Verkuil 	}
1327b285192aSMauro Carvalho Chehab 	return 0;
1328b285192aSMauro Carvalho Chehab }
1329b285192aSMauro Carvalho Chehab 
saa7134_s_selection(struct file * file,void * f,struct v4l2_selection * sel)1330802d62c1SHans Verkuil static int saa7134_s_selection(struct file *file, void *f, struct v4l2_selection *sel)
1331b285192aSMauro Carvalho Chehab {
1332b9f63b25SHans Verkuil 	struct saa7134_dev *dev = video_drvdata(file);
1333b285192aSMauro Carvalho Chehab 	struct v4l2_rect *b = &dev->crop_bounds;
13344f996594SHans Verkuil 	struct v4l2_rect *c = &dev->crop_current;
1335b285192aSMauro Carvalho Chehab 
133650a5677dSHans Verkuil 	if (sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1337802d62c1SHans Verkuil 		return -EINVAL;
1338802d62c1SHans Verkuil 
1339802d62c1SHans Verkuil 	if (sel->target != V4L2_SEL_TGT_CROP)
1340b285192aSMauro Carvalho Chehab 		return -EINVAL;
1341b285192aSMauro Carvalho Chehab 
13422ada815fSHans Verkuil 	if (vb2_is_streaming(&dev->video_vbq))
1343b285192aSMauro Carvalho Chehab 		return -EBUSY;
1344b285192aSMauro Carvalho Chehab 
1345802d62c1SHans Verkuil 	*c = sel->r;
13464f996594SHans Verkuil 	if (c->top < b->top)
13474f996594SHans Verkuil 		c->top = b->top;
13484f996594SHans Verkuil 	if (c->top > b->top + b->height)
13494f996594SHans Verkuil 		c->top = b->top + b->height;
13504f996594SHans Verkuil 	if (c->height > b->top - c->top + b->height)
13514f996594SHans Verkuil 		c->height = b->top - c->top + b->height;
1352b285192aSMauro Carvalho Chehab 
13534f996594SHans Verkuil 	if (c->left < b->left)
13544f996594SHans Verkuil 		c->left = b->left;
13554f996594SHans Verkuil 	if (c->left > b->left + b->width)
13564f996594SHans Verkuil 		c->left = b->left + b->width;
13574f996594SHans Verkuil 	if (c->width > b->left - c->left + b->width)
13584f996594SHans Verkuil 		c->width = b->left - c->left + b->width;
1359802d62c1SHans Verkuil 	sel->r = *c;
1360b285192aSMauro Carvalho Chehab 	return 0;
1361b285192aSMauro Carvalho Chehab }
1362b285192aSMauro Carvalho Chehab 
saa7134_g_tuner(struct file * file,void * priv,struct v4l2_tuner * t)1363b93a18d5SHans Verkuil int saa7134_g_tuner(struct file *file, void *priv,
1364b285192aSMauro Carvalho Chehab 					struct v4l2_tuner *t)
1365b285192aSMauro Carvalho Chehab {
1366b93a18d5SHans Verkuil 	struct saa7134_dev *dev = video_drvdata(file);
1367b285192aSMauro Carvalho Chehab 	int n;
1368b285192aSMauro Carvalho Chehab 
1369b285192aSMauro Carvalho Chehab 	if (0 != t->index)
1370b285192aSMauro Carvalho Chehab 		return -EINVAL;
1371b285192aSMauro Carvalho Chehab 	memset(t, 0, sizeof(*t));
1372b285192aSMauro Carvalho Chehab 	for (n = 0; n < SAA7134_INPUT_MAX; n++) {
13738bf77f9eSMauro Carvalho Chehab 		if (card_in(dev, n).type == SAA7134_INPUT_TV ||
13748bf77f9eSMauro Carvalho Chehab 		    card_in(dev, n).type == SAA7134_INPUT_TV_MONO)
1375b285192aSMauro Carvalho Chehab 			break;
1376b285192aSMauro Carvalho Chehab 	}
1377b285192aSMauro Carvalho Chehab 	if (n == SAA7134_INPUT_MAX)
1378b285192aSMauro Carvalho Chehab 		return -EINVAL;
13798fc34867SMauro Carvalho Chehab 	if (card_in(dev, n).type != SAA7134_NO_INPUT) {
1380cc1e6315SMauro Carvalho Chehab 		strscpy(t->name, "Television", sizeof(t->name));
1381b285192aSMauro Carvalho Chehab 		t->type = V4L2_TUNER_ANALOG_TV;
1382ce5bdd52SOndrej Zary 		saa_call_all(dev, tuner, g_tuner, t);
1383b285192aSMauro Carvalho Chehab 		t->capability = V4L2_TUNER_CAP_NORM |
1384b285192aSMauro Carvalho Chehab 			V4L2_TUNER_CAP_STEREO |
1385b285192aSMauro Carvalho Chehab 			V4L2_TUNER_CAP_LANG1 |
1386b285192aSMauro Carvalho Chehab 			V4L2_TUNER_CAP_LANG2;
1387b285192aSMauro Carvalho Chehab 		t->rxsubchans = saa7134_tvaudio_getstereo(dev);
1388b285192aSMauro Carvalho Chehab 		t->audmode = saa7134_tvaudio_rx2mode(t->rxsubchans);
1389b285192aSMauro Carvalho Chehab 	}
1390b285192aSMauro Carvalho Chehab 	if (0 != (saa_readb(SAA7134_STATUS_VIDEO1) & 0x03))
1391b285192aSMauro Carvalho Chehab 		t->signal = 0xffff;
1392b285192aSMauro Carvalho Chehab 	return 0;
1393b285192aSMauro Carvalho Chehab }
1394b93a18d5SHans Verkuil EXPORT_SYMBOL_GPL(saa7134_g_tuner);
1395b285192aSMauro Carvalho Chehab 
saa7134_s_tuner(struct file * file,void * priv,const struct v4l2_tuner * t)1396b93a18d5SHans Verkuil int saa7134_s_tuner(struct file *file, void *priv,
13972f73c7c5SHans Verkuil 					const struct v4l2_tuner *t)
1398b285192aSMauro Carvalho Chehab {
1399b93a18d5SHans Verkuil 	struct saa7134_dev *dev = video_drvdata(file);
14003bbaa3a6SOndrej Zary 	int rx, mode;
1401b285192aSMauro Carvalho Chehab 
1402ce5bdd52SOndrej Zary 	if (0 != t->index)
1403ce5bdd52SOndrej Zary 		return -EINVAL;
1404ce5bdd52SOndrej Zary 
1405b285192aSMauro Carvalho Chehab 	mode = dev->thread.mode;
1406b285192aSMauro Carvalho Chehab 	if (UNSET == mode) {
1407b285192aSMauro Carvalho Chehab 		rx   = saa7134_tvaudio_getstereo(dev);
1408b285192aSMauro Carvalho Chehab 		mode = saa7134_tvaudio_rx2mode(rx);
1409b285192aSMauro Carvalho Chehab 	}
1410b285192aSMauro Carvalho Chehab 	if (mode != t->audmode)
1411b285192aSMauro Carvalho Chehab 		dev->thread.mode = t->audmode;
1412b285192aSMauro Carvalho Chehab 
1413b285192aSMauro Carvalho Chehab 	return 0;
1414b285192aSMauro Carvalho Chehab }
1415b93a18d5SHans Verkuil EXPORT_SYMBOL_GPL(saa7134_s_tuner);
1416b285192aSMauro Carvalho Chehab 
saa7134_g_frequency(struct file * file,void * priv,struct v4l2_frequency * f)1417b93a18d5SHans Verkuil int saa7134_g_frequency(struct file *file, void *priv,
1418b285192aSMauro Carvalho Chehab 					struct v4l2_frequency *f)
1419b285192aSMauro Carvalho Chehab {
1420b93a18d5SHans Verkuil 	struct saa7134_dev *dev = video_drvdata(file);
1421b285192aSMauro Carvalho Chehab 
14220a5ea88bSOndrej Zary 	if (0 != f->tuner)
14230a5ea88bSOndrej Zary 		return -EINVAL;
14240a5ea88bSOndrej Zary 
14250a5ea88bSOndrej Zary 	saa_call_all(dev, tuner, g_frequency, f);
1426b285192aSMauro Carvalho Chehab 
1427b285192aSMauro Carvalho Chehab 	return 0;
1428b285192aSMauro Carvalho Chehab }
1429b93a18d5SHans Verkuil EXPORT_SYMBOL_GPL(saa7134_g_frequency);
1430b285192aSMauro Carvalho Chehab 
saa7134_s_frequency(struct file * file,void * priv,const struct v4l2_frequency * f)1431b93a18d5SHans Verkuil int saa7134_s_frequency(struct file *file, void *priv,
1432b530a447SHans Verkuil 					const struct v4l2_frequency *f)
1433b285192aSMauro Carvalho Chehab {
1434b93a18d5SHans Verkuil 	struct saa7134_dev *dev = video_drvdata(file);
1435b285192aSMauro Carvalho Chehab 
1436b285192aSMauro Carvalho Chehab 	if (0 != f->tuner)
1437b285192aSMauro Carvalho Chehab 		return -EINVAL;
1438b285192aSMauro Carvalho Chehab 
1439b285192aSMauro Carvalho Chehab 	saa_call_all(dev, tuner, s_frequency, f);
1440b285192aSMauro Carvalho Chehab 
1441b285192aSMauro Carvalho Chehab 	saa7134_tvaudio_do_scan(dev);
1442b285192aSMauro Carvalho Chehab 	return 0;
1443b285192aSMauro Carvalho Chehab }
1444b93a18d5SHans Verkuil EXPORT_SYMBOL_GPL(saa7134_s_frequency);
1445b285192aSMauro Carvalho Chehab 
saa7134_enum_fmt_vid_cap(struct file * file,void * priv,struct v4l2_fmtdesc * f)1446b285192aSMauro Carvalho Chehab static int saa7134_enum_fmt_vid_cap(struct file *file, void  *priv,
1447b285192aSMauro Carvalho Chehab 					struct v4l2_fmtdesc *f)
1448b285192aSMauro Carvalho Chehab {
1449b285192aSMauro Carvalho Chehab 	if (f->index >= FORMATS)
1450b285192aSMauro Carvalho Chehab 		return -EINVAL;
1451b285192aSMauro Carvalho Chehab 
1452b285192aSMauro Carvalho Chehab 	f->pixelformat = formats[f->index].fourcc;
1453b285192aSMauro Carvalho Chehab 
1454b285192aSMauro Carvalho Chehab 	return 0;
1455b285192aSMauro Carvalho Chehab }
1456b285192aSMauro Carvalho Chehab 
1457b285192aSMauro Carvalho Chehab #ifdef CONFIG_VIDEO_ADV_DEBUG
vidioc_g_register(struct file * file,void * priv,struct v4l2_dbg_register * reg)1458b285192aSMauro Carvalho Chehab static int vidioc_g_register (struct file *file, void *priv,
1459b285192aSMauro Carvalho Chehab 			      struct v4l2_dbg_register *reg)
1460b285192aSMauro Carvalho Chehab {
1461b9f63b25SHans Verkuil 	struct saa7134_dev *dev = video_drvdata(file);
1462b285192aSMauro Carvalho Chehab 
1463b8300702SHans Verkuil 	reg->val = saa_readb(reg->reg & 0xffffff);
1464b285192aSMauro Carvalho Chehab 	reg->size = 1;
1465b285192aSMauro Carvalho Chehab 	return 0;
1466b285192aSMauro Carvalho Chehab }
1467b285192aSMauro Carvalho Chehab 
vidioc_s_register(struct file * file,void * priv,const struct v4l2_dbg_register * reg)1468b285192aSMauro Carvalho Chehab static int vidioc_s_register (struct file *file, void *priv,
1469977ba3b1SHans Verkuil 				const struct v4l2_dbg_register *reg)
1470b285192aSMauro Carvalho Chehab {
1471b9f63b25SHans Verkuil 	struct saa7134_dev *dev = video_drvdata(file);
1472b285192aSMauro Carvalho Chehab 
1473b285192aSMauro Carvalho Chehab 	saa_writeb(reg->reg & 0xffffff, reg->val);
1474b285192aSMauro Carvalho Chehab 	return 0;
1475b285192aSMauro Carvalho Chehab }
1476b285192aSMauro Carvalho Chehab #endif
1477b285192aSMauro Carvalho Chehab 
radio_g_tuner(struct file * file,void * priv,struct v4l2_tuner * t)1478b285192aSMauro Carvalho Chehab static int radio_g_tuner(struct file *file, void *priv,
1479b285192aSMauro Carvalho Chehab 					struct v4l2_tuner *t)
1480b285192aSMauro Carvalho Chehab {
1481b9f63b25SHans Verkuil 	struct saa7134_dev *dev = video_drvdata(file);
1482b285192aSMauro Carvalho Chehab 
1483b285192aSMauro Carvalho Chehab 	if (0 != t->index)
1484b285192aSMauro Carvalho Chehab 		return -EINVAL;
1485b285192aSMauro Carvalho Chehab 
1486cc1e6315SMauro Carvalho Chehab 	strscpy(t->name, "Radio", sizeof(t->name));
1487b285192aSMauro Carvalho Chehab 
1488b285192aSMauro Carvalho Chehab 	saa_call_all(dev, tuner, g_tuner, t);
148982456708SOndrej Zary 	t->audmode &= V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO;
1490b285192aSMauro Carvalho Chehab 	if (dev->input->amux == TV) {
1491b285192aSMauro Carvalho Chehab 		t->signal = 0xf800 - ((saa_readb(0x581) & 0x1f) << 11);
1492b285192aSMauro Carvalho Chehab 		t->rxsubchans = (saa_readb(0x529) & 0x08) ?
1493b285192aSMauro Carvalho Chehab 				V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO;
1494b285192aSMauro Carvalho Chehab 	}
1495b285192aSMauro Carvalho Chehab 	return 0;
1496b285192aSMauro Carvalho Chehab }
radio_s_tuner(struct file * file,void * priv,const struct v4l2_tuner * t)1497b285192aSMauro Carvalho Chehab static int radio_s_tuner(struct file *file, void *priv,
14982f73c7c5SHans Verkuil 					const struct v4l2_tuner *t)
1499b285192aSMauro Carvalho Chehab {
1500b9f63b25SHans Verkuil 	struct saa7134_dev *dev = video_drvdata(file);
1501b285192aSMauro Carvalho Chehab 
1502b285192aSMauro Carvalho Chehab 	if (0 != t->index)
1503b285192aSMauro Carvalho Chehab 		return -EINVAL;
1504b285192aSMauro Carvalho Chehab 
1505b285192aSMauro Carvalho Chehab 	saa_call_all(dev, tuner, s_tuner, t);
1506b285192aSMauro Carvalho Chehab 	return 0;
1507b285192aSMauro Carvalho Chehab }
1508b285192aSMauro Carvalho Chehab 
1509b285192aSMauro Carvalho Chehab static const struct v4l2_file_operations video_fops =
1510b285192aSMauro Carvalho Chehab {
1511b285192aSMauro Carvalho Chehab 	.owner	  = THIS_MODULE,
1512b285192aSMauro Carvalho Chehab 	.open	  = video_open,
1513b285192aSMauro Carvalho Chehab 	.release  = video_release,
15142ada815fSHans Verkuil 	.read	  = vb2_fop_read,
15152ada815fSHans Verkuil 	.poll     = vb2_fop_poll,
15162ada815fSHans Verkuil 	.mmap	  = vb2_fop_mmap,
15172ada815fSHans Verkuil 	.unlocked_ioctl	  = video_ioctl2,
1518b285192aSMauro Carvalho Chehab };
1519b285192aSMauro Carvalho Chehab 
1520b285192aSMauro Carvalho Chehab static const struct v4l2_ioctl_ops video_ioctl_ops = {
1521b285192aSMauro Carvalho Chehab 	.vidioc_querycap		= saa7134_querycap,
1522b285192aSMauro Carvalho Chehab 	.vidioc_enum_fmt_vid_cap	= saa7134_enum_fmt_vid_cap,
1523b285192aSMauro Carvalho Chehab 	.vidioc_g_fmt_vid_cap		= saa7134_g_fmt_vid_cap,
1524b285192aSMauro Carvalho Chehab 	.vidioc_try_fmt_vid_cap		= saa7134_try_fmt_vid_cap,
1525b285192aSMauro Carvalho Chehab 	.vidioc_s_fmt_vid_cap		= saa7134_s_fmt_vid_cap,
1526b285192aSMauro Carvalho Chehab 	.vidioc_g_fmt_vbi_cap		= saa7134_try_get_set_fmt_vbi_cap,
1527b285192aSMauro Carvalho Chehab 	.vidioc_try_fmt_vbi_cap		= saa7134_try_get_set_fmt_vbi_cap,
1528b285192aSMauro Carvalho Chehab 	.vidioc_s_fmt_vbi_cap		= saa7134_try_get_set_fmt_vbi_cap,
15295200ab6aSHans Verkuil 	.vidioc_g_pixelaspect		= saa7134_g_pixelaspect,
15302ada815fSHans Verkuil 	.vidioc_reqbufs			= vb2_ioctl_reqbufs,
15312ada815fSHans Verkuil 	.vidioc_querybuf		= vb2_ioctl_querybuf,
15322ada815fSHans Verkuil 	.vidioc_qbuf			= vb2_ioctl_qbuf,
15332ada815fSHans Verkuil 	.vidioc_dqbuf			= vb2_ioctl_dqbuf,
15349f183020SHans Verkuil 	.vidioc_expbuf			= vb2_ioctl_expbuf,
1535b285192aSMauro Carvalho Chehab 	.vidioc_s_std			= saa7134_s_std,
1536b285192aSMauro Carvalho Chehab 	.vidioc_g_std			= saa7134_g_std,
1537707b7f80SMikhail Domrachev 	.vidioc_querystd		= saa7134_querystd,
1538b285192aSMauro Carvalho Chehab 	.vidioc_enum_input		= saa7134_enum_input,
1539b285192aSMauro Carvalho Chehab 	.vidioc_g_input			= saa7134_g_input,
1540b285192aSMauro Carvalho Chehab 	.vidioc_s_input			= saa7134_s_input,
15412ada815fSHans Verkuil 	.vidioc_streamon		= vb2_ioctl_streamon,
15422ada815fSHans Verkuil 	.vidioc_streamoff		= vb2_ioctl_streamoff,
1543b285192aSMauro Carvalho Chehab 	.vidioc_g_tuner			= saa7134_g_tuner,
1544b285192aSMauro Carvalho Chehab 	.vidioc_s_tuner			= saa7134_s_tuner,
1545802d62c1SHans Verkuil 	.vidioc_g_selection		= saa7134_g_selection,
1546802d62c1SHans Verkuil 	.vidioc_s_selection		= saa7134_s_selection,
1547b285192aSMauro Carvalho Chehab 	.vidioc_g_frequency		= saa7134_g_frequency,
1548b285192aSMauro Carvalho Chehab 	.vidioc_s_frequency		= saa7134_s_frequency,
1549b285192aSMauro Carvalho Chehab #ifdef CONFIG_VIDEO_ADV_DEBUG
1550b285192aSMauro Carvalho Chehab 	.vidioc_g_register              = vidioc_g_register,
1551b285192aSMauro Carvalho Chehab 	.vidioc_s_register              = vidioc_s_register,
1552b285192aSMauro Carvalho Chehab #endif
1553a2004502SHans Verkuil 	.vidioc_log_status		= v4l2_ctrl_log_status,
1554a2004502SHans Verkuil 	.vidioc_subscribe_event		= v4l2_ctrl_subscribe_event,
1555a2004502SHans Verkuil 	.vidioc_unsubscribe_event	= v4l2_event_unsubscribe,
1556b285192aSMauro Carvalho Chehab };
1557b285192aSMauro Carvalho Chehab 
1558b285192aSMauro Carvalho Chehab static const struct v4l2_file_operations radio_fops = {
1559b285192aSMauro Carvalho Chehab 	.owner	  = THIS_MODULE,
1560b285192aSMauro Carvalho Chehab 	.open	  = video_open,
1561b285192aSMauro Carvalho Chehab 	.read     = radio_read,
1562b285192aSMauro Carvalho Chehab 	.release  = video_release,
15632ada815fSHans Verkuil 	.unlocked_ioctl	= video_ioctl2,
1564b285192aSMauro Carvalho Chehab 	.poll     = radio_poll,
1565b285192aSMauro Carvalho Chehab };
1566b285192aSMauro Carvalho Chehab 
1567b285192aSMauro Carvalho Chehab static const struct v4l2_ioctl_ops radio_ioctl_ops = {
1568c3b3e0c5SOndrej Zary 	.vidioc_querycap	= saa7134_querycap,
1569b285192aSMauro Carvalho Chehab 	.vidioc_g_tuner		= radio_g_tuner,
1570b285192aSMauro Carvalho Chehab 	.vidioc_s_tuner		= radio_s_tuner,
1571b285192aSMauro Carvalho Chehab 	.vidioc_g_frequency	= saa7134_g_frequency,
1572b285192aSMauro Carvalho Chehab 	.vidioc_s_frequency	= saa7134_s_frequency,
1573a2004502SHans Verkuil 	.vidioc_subscribe_event	= v4l2_ctrl_subscribe_event,
1574a2004502SHans Verkuil 	.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
1575b285192aSMauro Carvalho Chehab };
1576b285192aSMauro Carvalho Chehab 
1577b285192aSMauro Carvalho Chehab /* ----------------------------------------------------------- */
1578b285192aSMauro Carvalho Chehab /* exported stuff                                              */
1579b285192aSMauro Carvalho Chehab 
1580b285192aSMauro Carvalho Chehab struct video_device saa7134_video_template = {
1581b285192aSMauro Carvalho Chehab 	.name				= "saa7134-video",
1582b285192aSMauro Carvalho Chehab 	.fops				= &video_fops,
1583b285192aSMauro Carvalho Chehab 	.ioctl_ops			= &video_ioctl_ops,
1584b285192aSMauro Carvalho Chehab 	.tvnorms			= SAA7134_NORMS,
1585b285192aSMauro Carvalho Chehab };
1586b285192aSMauro Carvalho Chehab 
1587b285192aSMauro Carvalho Chehab struct video_device saa7134_radio_template = {
1588b285192aSMauro Carvalho Chehab 	.name			= "saa7134-radio",
1589b285192aSMauro Carvalho Chehab 	.fops			= &radio_fops,
1590b285192aSMauro Carvalho Chehab 	.ioctl_ops		= &radio_ioctl_ops,
1591b285192aSMauro Carvalho Chehab };
1592b285192aSMauro Carvalho Chehab 
1593718bde1aSHans Verkuil static const struct v4l2_ctrl_ops saa7134_ctrl_ops = {
1594718bde1aSHans Verkuil 	.s_ctrl = saa7134_s_ctrl,
1595718bde1aSHans Verkuil };
1596718bde1aSHans Verkuil 
1597718bde1aSHans Verkuil static const struct v4l2_ctrl_config saa7134_ctrl_invert = {
1598718bde1aSHans Verkuil 	.ops = &saa7134_ctrl_ops,
1599718bde1aSHans Verkuil 	.id = V4L2_CID_PRIVATE_INVERT,
1600718bde1aSHans Verkuil 	.name = "Invert",
1601718bde1aSHans Verkuil 	.type = V4L2_CTRL_TYPE_BOOLEAN,
1602718bde1aSHans Verkuil 	.min = 0,
1603718bde1aSHans Verkuil 	.max = 1,
1604718bde1aSHans Verkuil 	.step = 1,
1605718bde1aSHans Verkuil };
1606718bde1aSHans Verkuil 
1607718bde1aSHans Verkuil static const struct v4l2_ctrl_config saa7134_ctrl_y_odd = {
1608718bde1aSHans Verkuil 	.ops = &saa7134_ctrl_ops,
1609718bde1aSHans Verkuil 	.id = V4L2_CID_PRIVATE_Y_ODD,
1610718bde1aSHans Verkuil 	.name = "Y Offset Odd Field",
1611718bde1aSHans Verkuil 	.type = V4L2_CTRL_TYPE_INTEGER,
1612718bde1aSHans Verkuil 	.min = 0,
1613718bde1aSHans Verkuil 	.max = 128,
1614718bde1aSHans Verkuil 	.step = 1,
1615718bde1aSHans Verkuil };
1616718bde1aSHans Verkuil 
1617718bde1aSHans Verkuil static const struct v4l2_ctrl_config saa7134_ctrl_y_even = {
1618718bde1aSHans Verkuil 	.ops = &saa7134_ctrl_ops,
1619718bde1aSHans Verkuil 	.id = V4L2_CID_PRIVATE_Y_EVEN,
1620718bde1aSHans Verkuil 	.name = "Y Offset Even Field",
1621718bde1aSHans Verkuil 	.type = V4L2_CTRL_TYPE_INTEGER,
1622718bde1aSHans Verkuil 	.min = 0,
1623718bde1aSHans Verkuil 	.max = 128,
1624718bde1aSHans Verkuil 	.step = 1,
1625718bde1aSHans Verkuil };
1626718bde1aSHans Verkuil 
1627718bde1aSHans Verkuil static const struct v4l2_ctrl_config saa7134_ctrl_automute = {
1628718bde1aSHans Verkuil 	.ops = &saa7134_ctrl_ops,
1629718bde1aSHans Verkuil 	.id = V4L2_CID_PRIVATE_AUTOMUTE,
1630718bde1aSHans Verkuil 	.name = "Automute",
1631718bde1aSHans Verkuil 	.type = V4L2_CTRL_TYPE_BOOLEAN,
1632718bde1aSHans Verkuil 	.min = 0,
1633718bde1aSHans Verkuil 	.max = 1,
1634718bde1aSHans Verkuil 	.step = 1,
1635718bde1aSHans Verkuil 	.def = 1,
1636718bde1aSHans Verkuil };
1637718bde1aSHans Verkuil 
saa7134_video_init1(struct saa7134_dev * dev)1638b285192aSMauro Carvalho Chehab int saa7134_video_init1(struct saa7134_dev *dev)
1639b285192aSMauro Carvalho Chehab {
1640718bde1aSHans Verkuil 	struct v4l2_ctrl_handler *hdl = &dev->ctrl_handler;
16412ada815fSHans Verkuil 	struct vb2_queue *q;
16422ada815fSHans Verkuil 	int ret;
1643718bde1aSHans Verkuil 
1644b285192aSMauro Carvalho Chehab 	/* sanitycheck insmod options */
1645b285192aSMauro Carvalho Chehab 	if (gbuffers < 2 || gbuffers > VIDEO_MAX_FRAME)
1646b285192aSMauro Carvalho Chehab 		gbuffers = 2;
16473eeba4a7SMauro Carvalho Chehab 	if (gbufsize > gbufsize_max)
1648b285192aSMauro Carvalho Chehab 		gbufsize = gbufsize_max;
1649b285192aSMauro Carvalho Chehab 	gbufsize = (gbufsize + PAGE_SIZE - 1) & PAGE_MASK;
1650b285192aSMauro Carvalho Chehab 
1651718bde1aSHans Verkuil 	v4l2_ctrl_handler_init(hdl, 11);
1652718bde1aSHans Verkuil 	v4l2_ctrl_new_std(hdl, &saa7134_ctrl_ops,
1653718bde1aSHans Verkuil 			V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
1654718bde1aSHans Verkuil 	v4l2_ctrl_new_std(hdl, &saa7134_ctrl_ops,
1655718bde1aSHans Verkuil 			V4L2_CID_CONTRAST, 0, 127, 1, 68);
1656718bde1aSHans Verkuil 	v4l2_ctrl_new_std(hdl, &saa7134_ctrl_ops,
1657718bde1aSHans Verkuil 			V4L2_CID_SATURATION, 0, 127, 1, 64);
1658718bde1aSHans Verkuil 	v4l2_ctrl_new_std(hdl, &saa7134_ctrl_ops,
1659718bde1aSHans Verkuil 			V4L2_CID_HUE, -128, 127, 1, 0);
1660718bde1aSHans Verkuil 	v4l2_ctrl_new_std(hdl, &saa7134_ctrl_ops,
1661718bde1aSHans Verkuil 			V4L2_CID_HFLIP, 0, 1, 1, 0);
1662718bde1aSHans Verkuil 	v4l2_ctrl_new_std(hdl, &saa7134_ctrl_ops,
1663718bde1aSHans Verkuil 			V4L2_CID_AUDIO_MUTE, 0, 1, 1, 0);
1664718bde1aSHans Verkuil 	v4l2_ctrl_new_std(hdl, &saa7134_ctrl_ops,
1665718bde1aSHans Verkuil 			V4L2_CID_AUDIO_VOLUME, -15, 15, 1, 0);
1666718bde1aSHans Verkuil 	v4l2_ctrl_new_custom(hdl, &saa7134_ctrl_invert, NULL);
1667718bde1aSHans Verkuil 	v4l2_ctrl_new_custom(hdl, &saa7134_ctrl_y_odd, NULL);
1668718bde1aSHans Verkuil 	v4l2_ctrl_new_custom(hdl, &saa7134_ctrl_y_even, NULL);
1669718bde1aSHans Verkuil 	v4l2_ctrl_new_custom(hdl, &saa7134_ctrl_automute, NULL);
1670718bde1aSHans Verkuil 	if (hdl->error)
1671718bde1aSHans Verkuil 		return hdl->error;
1672718bde1aSHans Verkuil 	if (card_has_radio(dev)) {
1673718bde1aSHans Verkuil 		hdl = &dev->radio_ctrl_handler;
1674718bde1aSHans Verkuil 		v4l2_ctrl_handler_init(hdl, 2);
1675718bde1aSHans Verkuil 		v4l2_ctrl_add_handler(hdl, &dev->ctrl_handler,
1676da1b1aeaSHans Verkuil 				v4l2_ctrl_radio_filter, false);
1677718bde1aSHans Verkuil 		if (hdl->error)
1678718bde1aSHans Verkuil 			return hdl->error;
1679718bde1aSHans Verkuil 	}
1680718bde1aSHans Verkuil 	dev->ctl_mute       = 1;
1681b285192aSMauro Carvalho Chehab 
1682718bde1aSHans Verkuil 	if (dev->tda9887_conf && saa7134_ctrl_automute.def)
1683b285192aSMauro Carvalho Chehab 		dev->tda9887_conf |= TDA9887_AUTOMUTE;
1684b285192aSMauro Carvalho Chehab 	dev->automute       = 0;
1685b285192aSMauro Carvalho Chehab 
1686b285192aSMauro Carvalho Chehab 	INIT_LIST_HEAD(&dev->video_q.queue);
16871e7126b4SKees Cook 	timer_setup(&dev->video_q.timeout, saa7134_buffer_timeout, 0);
1688b285192aSMauro Carvalho Chehab 	dev->video_q.dev              = dev;
1689813b9dffSHans Verkuil 	dev->fmt = format_by_fourcc(V4L2_PIX_FMT_BGR24);
1690813b9dffSHans Verkuil 	dev->width    = 720;
1691813b9dffSHans Verkuil 	dev->height   = 576;
16922ada815fSHans Verkuil 	dev->field = V4L2_FIELD_INTERLACED;
1693b285192aSMauro Carvalho Chehab 
1694b285192aSMauro Carvalho Chehab 	if (saa7134_boards[dev->board].video_out)
1695b285192aSMauro Carvalho Chehab 		saa7134_videoport_init(dev);
1696b285192aSMauro Carvalho Chehab 
16972ada815fSHans Verkuil 	q = &dev->video_vbq;
16982ada815fSHans Verkuil 	q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
16992ada815fSHans Verkuil 	/*
1700a3f415abSHans Verkuil 	 * Do not add VB2_USERPTR unless explicitly requested: the saa7134 DMA
1701a3f415abSHans Verkuil 	 * engine cannot handle transfers that do not start at the beginning
1702a3f415abSHans Verkuil 	 * of a page. A user-provided pointer can start anywhere in a page, so
1703a3f415abSHans Verkuil 	 * USERPTR support is a no-go unless the application knows about these
1704a3f415abSHans Verkuil 	 * limitations and has special support for this.
17052ada815fSHans Verkuil 	 */
17069f183020SHans Verkuil 	q->io_modes = VB2_MMAP | VB2_DMABUF | VB2_READ;
1707a3f415abSHans Verkuil 	if (saa7134_userptr)
1708a3f415abSHans Verkuil 		q->io_modes |= VB2_USERPTR;
17092ada815fSHans Verkuil 	q->drv_priv = &dev->video_q;
17102ada815fSHans Verkuil 	q->ops = &vb2_qops;
17112ada815fSHans Verkuil 	q->gfp_flags = GFP_DMA32;
17122ada815fSHans Verkuil 	q->mem_ops = &vb2_dma_sg_memops;
17132ada815fSHans Verkuil 	q->buf_struct_size = sizeof(struct saa7134_buf);
17142ada815fSHans Verkuil 	q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
17152ada815fSHans Verkuil 	q->lock = &dev->lock;
17162bc46b3aSHans Verkuil 	q->dev = &dev->pci->dev;
17172ada815fSHans Verkuil 	ret = vb2_queue_init(q);
17182ada815fSHans Verkuil 	if (ret)
17192ada815fSHans Verkuil 		return ret;
1720a00e6888SHans Verkuil 	saa7134_pgtable_alloc(dev->pci, &dev->video_q.pt);
17212ada815fSHans Verkuil 
17222ada815fSHans Verkuil 	q = &dev->vbi_vbq;
17232ada815fSHans Verkuil 	q->type = V4L2_BUF_TYPE_VBI_CAPTURE;
17242ada815fSHans Verkuil 	/* Don't add VB2_USERPTR, see comment above */
17252ada815fSHans Verkuil 	q->io_modes = VB2_MMAP | VB2_READ;
1726a3f415abSHans Verkuil 	if (saa7134_userptr)
1727a3f415abSHans Verkuil 		q->io_modes |= VB2_USERPTR;
17282ada815fSHans Verkuil 	q->drv_priv = &dev->vbi_q;
17292ada815fSHans Verkuil 	q->ops = &saa7134_vbi_qops;
17302ada815fSHans Verkuil 	q->gfp_flags = GFP_DMA32;
17312ada815fSHans Verkuil 	q->mem_ops = &vb2_dma_sg_memops;
17322ada815fSHans Verkuil 	q->buf_struct_size = sizeof(struct saa7134_buf);
17332ada815fSHans Verkuil 	q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
17342ada815fSHans Verkuil 	q->lock = &dev->lock;
17352bc46b3aSHans Verkuil 	q->dev = &dev->pci->dev;
17362ada815fSHans Verkuil 	ret = vb2_queue_init(q);
17372ada815fSHans Verkuil 	if (ret)
17382ada815fSHans Verkuil 		return ret;
1739a00e6888SHans Verkuil 	saa7134_pgtable_alloc(dev->pci, &dev->vbi_q.pt);
17409db0fb18SHans Verkuil 
1741b285192aSMauro Carvalho Chehab 	return 0;
1742b285192aSMauro Carvalho Chehab }
1743b285192aSMauro Carvalho Chehab 
saa7134_video_fini(struct saa7134_dev * dev)17449db0fb18SHans Verkuil void saa7134_video_fini(struct saa7134_dev *dev)
17459db0fb18SHans Verkuil {
1746*30cf57daSZheng Wang 	del_timer_sync(&dev->video_q.timeout);
17479db0fb18SHans Verkuil 	/* free stuff */
1748a00e6888SHans Verkuil 	saa7134_pgtable_free(dev->pci, &dev->video_q.pt);
1749a00e6888SHans Verkuil 	saa7134_pgtable_free(dev->pci, &dev->vbi_q.pt);
1750718bde1aSHans Verkuil 	v4l2_ctrl_handler_free(&dev->ctrl_handler);
1751718bde1aSHans Verkuil 	if (card_has_radio(dev))
1752718bde1aSHans Verkuil 		v4l2_ctrl_handler_free(&dev->radio_ctrl_handler);
17539db0fb18SHans Verkuil }
17549db0fb18SHans Verkuil 
saa7134_videoport_init(struct saa7134_dev * dev)1755b285192aSMauro Carvalho Chehab int saa7134_videoport_init(struct saa7134_dev *dev)
1756b285192aSMauro Carvalho Chehab {
1757b285192aSMauro Carvalho Chehab 	/* enable video output */
1758b285192aSMauro Carvalho Chehab 	int vo = saa7134_boards[dev->board].video_out;
1759b285192aSMauro Carvalho Chehab 	int video_reg;
1760b285192aSMauro Carvalho Chehab 	unsigned int vid_port_opts = saa7134_boards[dev->board].vid_port_opts;
1761b285192aSMauro Carvalho Chehab 
1762b285192aSMauro Carvalho Chehab 	/* Configure videoport */
1763b285192aSMauro Carvalho Chehab 	saa_writeb(SAA7134_VIDEO_PORT_CTRL0, video_out[vo][0]);
1764b285192aSMauro Carvalho Chehab 	video_reg = video_out[vo][1];
1765b285192aSMauro Carvalho Chehab 	if (vid_port_opts & SET_T_CODE_POLARITY_NON_INVERTED)
1766b285192aSMauro Carvalho Chehab 		video_reg &= ~VP_T_CODE_P_INVERTED;
1767b285192aSMauro Carvalho Chehab 	saa_writeb(SAA7134_VIDEO_PORT_CTRL1, video_reg);
1768b285192aSMauro Carvalho Chehab 	saa_writeb(SAA7134_VIDEO_PORT_CTRL2, video_out[vo][2]);
1769b285192aSMauro Carvalho Chehab 	saa_writeb(SAA7134_VIDEO_PORT_CTRL4, video_out[vo][4]);
1770b285192aSMauro Carvalho Chehab 	video_reg = video_out[vo][5];
1771b285192aSMauro Carvalho Chehab 	if (vid_port_opts & SET_CLOCK_NOT_DELAYED)
1772b285192aSMauro Carvalho Chehab 		video_reg &= ~VP_CLK_CTRL2_DELAYED;
1773b285192aSMauro Carvalho Chehab 	if (vid_port_opts & SET_CLOCK_INVERTED)
1774b285192aSMauro Carvalho Chehab 		video_reg |= VP_CLK_CTRL1_INVERTED;
1775b285192aSMauro Carvalho Chehab 	saa_writeb(SAA7134_VIDEO_PORT_CTRL5, video_reg);
1776b285192aSMauro Carvalho Chehab 	video_reg = video_out[vo][6];
1777b285192aSMauro Carvalho Chehab 	if (vid_port_opts & SET_VSYNC_OFF) {
1778b285192aSMauro Carvalho Chehab 		video_reg &= ~VP_VS_TYPE_MASK;
1779b285192aSMauro Carvalho Chehab 		video_reg |= VP_VS_TYPE_OFF;
1780b285192aSMauro Carvalho Chehab 	}
1781b285192aSMauro Carvalho Chehab 	saa_writeb(SAA7134_VIDEO_PORT_CTRL6, video_reg);
1782b285192aSMauro Carvalho Chehab 	saa_writeb(SAA7134_VIDEO_PORT_CTRL7, video_out[vo][7]);
1783b285192aSMauro Carvalho Chehab 	saa_writeb(SAA7134_VIDEO_PORT_CTRL8, video_out[vo][8]);
1784b285192aSMauro Carvalho Chehab 
1785b285192aSMauro Carvalho Chehab 	/* Start videoport */
1786b285192aSMauro Carvalho Chehab 	saa_writeb(SAA7134_VIDEO_PORT_CTRL3, video_out[vo][3]);
1787b285192aSMauro Carvalho Chehab 
1788b285192aSMauro Carvalho Chehab 	return 0;
1789b285192aSMauro Carvalho Chehab }
1790b285192aSMauro Carvalho Chehab 
saa7134_video_init2(struct saa7134_dev * dev)1791b285192aSMauro Carvalho Chehab int saa7134_video_init2(struct saa7134_dev *dev)
1792b285192aSMauro Carvalho Chehab {
1793b285192aSMauro Carvalho Chehab 	/* init video hw */
1794b285192aSMauro Carvalho Chehab 	set_tvnorm(dev,&tvnorms[0]);
1795b285192aSMauro Carvalho Chehab 	video_mux(dev,0);
1796718bde1aSHans Verkuil 	v4l2_ctrl_handler_setup(&dev->ctrl_handler);
1797b285192aSMauro Carvalho Chehab 	saa7134_tvaudio_setmute(dev);
1798b285192aSMauro Carvalho Chehab 	saa7134_tvaudio_setvolume(dev,dev->ctl_volume);
1799b285192aSMauro Carvalho Chehab 	return 0;
1800b285192aSMauro Carvalho Chehab }
1801b285192aSMauro Carvalho Chehab 
saa7134_irq_video_signalchange(struct saa7134_dev * dev)1802b285192aSMauro Carvalho Chehab void saa7134_irq_video_signalchange(struct saa7134_dev *dev)
1803b285192aSMauro Carvalho Chehab {
1804b285192aSMauro Carvalho Chehab 	static const char *st[] = {
1805b285192aSMauro Carvalho Chehab 		"(no signal)", "NTSC", "PAL", "SECAM" };
1806b285192aSMauro Carvalho Chehab 	u32 st1,st2;
1807b285192aSMauro Carvalho Chehab 
1808b285192aSMauro Carvalho Chehab 	st1 = saa_readb(SAA7134_STATUS_VIDEO1);
1809b285192aSMauro Carvalho Chehab 	st2 = saa_readb(SAA7134_STATUS_VIDEO2);
1810630983b7SMauro Carvalho Chehab 	video_dbg("DCSDT: pll: %s, sync: %s, norm: %s\n",
1811b285192aSMauro Carvalho Chehab 		(st1 & 0x40) ? "not locked" : "locked",
1812b285192aSMauro Carvalho Chehab 		(st2 & 0x40) ? "no"         : "yes",
1813b285192aSMauro Carvalho Chehab 		st[st1 & 0x03]);
1814b285192aSMauro Carvalho Chehab 	dev->nosignal = (st1 & 0x40) || (st2 & 0x40)  || !(st2 & 0x1);
1815b285192aSMauro Carvalho Chehab 
1816b285192aSMauro Carvalho Chehab 	if (dev->nosignal) {
1817b285192aSMauro Carvalho Chehab 		/* no video signal -> mute audio */
1818b285192aSMauro Carvalho Chehab 		if (dev->ctl_automute)
1819b285192aSMauro Carvalho Chehab 			dev->automute = 1;
1820b285192aSMauro Carvalho Chehab 		saa7134_tvaudio_setmute(dev);
1821b285192aSMauro Carvalho Chehab 	} else {
1822b285192aSMauro Carvalho Chehab 		/* wake up tvaudio audio carrier scan thread */
1823b285192aSMauro Carvalho Chehab 		saa7134_tvaudio_do_scan(dev);
1824b285192aSMauro Carvalho Chehab 	}
1825b285192aSMauro Carvalho Chehab 
1826b285192aSMauro Carvalho Chehab 	if ((st2 & 0x80) && !noninterlaced && !dev->nosignal)
1827b285192aSMauro Carvalho Chehab 		saa_clearb(SAA7134_SYNC_CTRL, 0x20);
1828b285192aSMauro Carvalho Chehab 	else
1829b285192aSMauro Carvalho Chehab 		saa_setb(SAA7134_SYNC_CTRL, 0x20);
1830b285192aSMauro Carvalho Chehab 
1831b285192aSMauro Carvalho Chehab 	if (dev->mops && dev->mops->signal_change)
1832b285192aSMauro Carvalho Chehab 		dev->mops->signal_change(dev);
1833b285192aSMauro Carvalho Chehab }
1834b285192aSMauro Carvalho Chehab 
1835b285192aSMauro Carvalho Chehab 
saa7134_irq_video_done(struct saa7134_dev * dev,unsigned long status)1836b285192aSMauro Carvalho Chehab void saa7134_irq_video_done(struct saa7134_dev *dev, unsigned long status)
1837b285192aSMauro Carvalho Chehab {
1838b285192aSMauro Carvalho Chehab 	enum v4l2_field field;
1839b285192aSMauro Carvalho Chehab 
1840b285192aSMauro Carvalho Chehab 	spin_lock(&dev->slock);
1841b285192aSMauro Carvalho Chehab 	if (dev->video_q.curr) {
18422ada815fSHans Verkuil 		field = dev->field;
1843b285192aSMauro Carvalho Chehab 		if (V4L2_FIELD_HAS_BOTH(field)) {
1844b285192aSMauro Carvalho Chehab 			/* make sure we have seen both fields */
1845b285192aSMauro Carvalho Chehab 			if ((status & 0x10) == 0x00) {
1846b285192aSMauro Carvalho Chehab 				dev->video_q.curr->top_seen = 1;
1847b285192aSMauro Carvalho Chehab 				goto done;
1848b285192aSMauro Carvalho Chehab 			}
1849b285192aSMauro Carvalho Chehab 			if (!dev->video_q.curr->top_seen)
1850b285192aSMauro Carvalho Chehab 				goto done;
1851b285192aSMauro Carvalho Chehab 		} else if (field == V4L2_FIELD_TOP) {
1852b285192aSMauro Carvalho Chehab 			if ((status & 0x10) != 0x10)
1853b285192aSMauro Carvalho Chehab 				goto done;
1854b285192aSMauro Carvalho Chehab 		} else if (field == V4L2_FIELD_BOTTOM) {
1855b285192aSMauro Carvalho Chehab 			if ((status & 0x10) != 0x00)
1856b285192aSMauro Carvalho Chehab 				goto done;
1857b285192aSMauro Carvalho Chehab 		}
18582ada815fSHans Verkuil 		saa7134_buffer_finish(dev, &dev->video_q, VB2_BUF_STATE_DONE);
1859b285192aSMauro Carvalho Chehab 	}
1860b285192aSMauro Carvalho Chehab 	saa7134_buffer_next(dev, &dev->video_q);
1861b285192aSMauro Carvalho Chehab 
1862b285192aSMauro Carvalho Chehab  done:
1863b285192aSMauro Carvalho Chehab 	spin_unlock(&dev->slock);
1864b285192aSMauro Carvalho Chehab }
1865