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