xref: /OK3568_Linux_fs/kernel/drivers/media/i2c/saa7127.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * saa7127 - Philips SAA7127/SAA7129 video encoder driver
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (C) 2003 Roy Bulter <rbulter@hetnet.nl>
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * Based on SAA7126 video encoder driver by Gillem & Andreas Oberritter
8*4882a593Smuzhiyun  *
9*4882a593Smuzhiyun  * Copyright (C) 2000-2001 Gillem <htoa@gmx.net>
10*4882a593Smuzhiyun  * Copyright (C) 2002 Andreas Oberritter <obi@saftware.de>
11*4882a593Smuzhiyun  *
12*4882a593Smuzhiyun  * Based on Stadis 4:2:2 MPEG-2 Decoder Driver by Nathan Laredo
13*4882a593Smuzhiyun  *
14*4882a593Smuzhiyun  * Copyright (C) 1999 Nathan Laredo <laredo@gnu.org>
15*4882a593Smuzhiyun  *
16*4882a593Smuzhiyun  * This driver is designed for the Hauppauge 250/350 Linux driver
17*4882a593Smuzhiyun  * from the ivtv Project
18*4882a593Smuzhiyun  *
19*4882a593Smuzhiyun  * Copyright (C) 2003 Kevin Thayer <nufan_wfk@yahoo.com>
20*4882a593Smuzhiyun  *
21*4882a593Smuzhiyun  * Dual output support:
22*4882a593Smuzhiyun  * Copyright (C) 2004 Eric Varsanyi
23*4882a593Smuzhiyun  *
24*4882a593Smuzhiyun  * NTSC Tuning and 7.5 IRE Setup
25*4882a593Smuzhiyun  * Copyright (C) 2004  Chris Kennedy <c@groovy.org>
26*4882a593Smuzhiyun  *
27*4882a593Smuzhiyun  * VBI additions & cleanup:
28*4882a593Smuzhiyun  * Copyright (C) 2004, 2005 Hans Verkuil <hverkuil@xs4all.nl>
29*4882a593Smuzhiyun  *
30*4882a593Smuzhiyun  * Note: the saa7126 is identical to the saa7127, and the saa7128 is
31*4882a593Smuzhiyun  * identical to the saa7129, except that the saa7126 and saa7128 have
32*4882a593Smuzhiyun  * macrovision anti-taping support. This driver will almost certainly
33*4882a593Smuzhiyun  * work fine for those chips, except of course for the missing anti-taping
34*4882a593Smuzhiyun  * support.
35*4882a593Smuzhiyun  */
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun #include <linux/kernel.h>
39*4882a593Smuzhiyun #include <linux/module.h>
40*4882a593Smuzhiyun #include <linux/slab.h>
41*4882a593Smuzhiyun #include <linux/i2c.h>
42*4882a593Smuzhiyun #include <linux/videodev2.h>
43*4882a593Smuzhiyun #include <media/v4l2-device.h>
44*4882a593Smuzhiyun #include <media/i2c/saa7127.h>
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun static int debug;
47*4882a593Smuzhiyun static int test_image;
48*4882a593Smuzhiyun 
49*4882a593Smuzhiyun MODULE_DESCRIPTION("Philips SAA7127/9 video encoder driver");
50*4882a593Smuzhiyun MODULE_AUTHOR("Kevin Thayer, Chris Kennedy, Hans Verkuil");
51*4882a593Smuzhiyun MODULE_LICENSE("GPL");
52*4882a593Smuzhiyun module_param(debug, int, 0644);
53*4882a593Smuzhiyun module_param(test_image, int, 0644);
54*4882a593Smuzhiyun MODULE_PARM_DESC(debug, "debug level (0-2)");
55*4882a593Smuzhiyun MODULE_PARM_DESC(test_image, "test_image (0-1)");
56*4882a593Smuzhiyun 
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun /*
59*4882a593Smuzhiyun  * SAA7127 registers
60*4882a593Smuzhiyun  */
61*4882a593Smuzhiyun 
62*4882a593Smuzhiyun #define SAA7127_REG_STATUS                           0x00
63*4882a593Smuzhiyun #define SAA7127_REG_WIDESCREEN_CONFIG                0x26
64*4882a593Smuzhiyun #define SAA7127_REG_WIDESCREEN_ENABLE                0x27
65*4882a593Smuzhiyun #define SAA7127_REG_BURST_START                      0x28
66*4882a593Smuzhiyun #define SAA7127_REG_BURST_END                        0x29
67*4882a593Smuzhiyun #define SAA7127_REG_COPYGEN_0                        0x2a
68*4882a593Smuzhiyun #define SAA7127_REG_COPYGEN_1                        0x2b
69*4882a593Smuzhiyun #define SAA7127_REG_COPYGEN_2                        0x2c
70*4882a593Smuzhiyun #define SAA7127_REG_OUTPUT_PORT_CONTROL              0x2d
71*4882a593Smuzhiyun #define SAA7127_REG_GAIN_LUMINANCE_RGB               0x38
72*4882a593Smuzhiyun #define SAA7127_REG_GAIN_COLORDIFF_RGB               0x39
73*4882a593Smuzhiyun #define SAA7127_REG_INPUT_PORT_CONTROL_1             0x3a
74*4882a593Smuzhiyun #define SAA7129_REG_FADE_KEY_COL2		     0x4f
75*4882a593Smuzhiyun #define SAA7127_REG_CHROMA_PHASE                     0x5a
76*4882a593Smuzhiyun #define SAA7127_REG_GAINU                            0x5b
77*4882a593Smuzhiyun #define SAA7127_REG_GAINV                            0x5c
78*4882a593Smuzhiyun #define SAA7127_REG_BLACK_LEVEL                      0x5d
79*4882a593Smuzhiyun #define SAA7127_REG_BLANKING_LEVEL                   0x5e
80*4882a593Smuzhiyun #define SAA7127_REG_VBI_BLANKING                     0x5f
81*4882a593Smuzhiyun #define SAA7127_REG_DAC_CONTROL                      0x61
82*4882a593Smuzhiyun #define SAA7127_REG_BURST_AMP                        0x62
83*4882a593Smuzhiyun #define SAA7127_REG_SUBC3                            0x63
84*4882a593Smuzhiyun #define SAA7127_REG_SUBC2                            0x64
85*4882a593Smuzhiyun #define SAA7127_REG_SUBC1                            0x65
86*4882a593Smuzhiyun #define SAA7127_REG_SUBC0                            0x66
87*4882a593Smuzhiyun #define SAA7127_REG_LINE_21_ODD_0                    0x67
88*4882a593Smuzhiyun #define SAA7127_REG_LINE_21_ODD_1                    0x68
89*4882a593Smuzhiyun #define SAA7127_REG_LINE_21_EVEN_0                   0x69
90*4882a593Smuzhiyun #define SAA7127_REG_LINE_21_EVEN_1                   0x6a
91*4882a593Smuzhiyun #define SAA7127_REG_RCV_PORT_CONTROL                 0x6b
92*4882a593Smuzhiyun #define SAA7127_REG_VTRIG                            0x6c
93*4882a593Smuzhiyun #define SAA7127_REG_HTRIG_HI                         0x6d
94*4882a593Smuzhiyun #define SAA7127_REG_MULTI                            0x6e
95*4882a593Smuzhiyun #define SAA7127_REG_CLOSED_CAPTION                   0x6f
96*4882a593Smuzhiyun #define SAA7127_REG_RCV2_OUTPUT_START                0x70
97*4882a593Smuzhiyun #define SAA7127_REG_RCV2_OUTPUT_END                  0x71
98*4882a593Smuzhiyun #define SAA7127_REG_RCV2_OUTPUT_MSBS                 0x72
99*4882a593Smuzhiyun #define SAA7127_REG_TTX_REQUEST_H_START              0x73
100*4882a593Smuzhiyun #define SAA7127_REG_TTX_REQUEST_H_DELAY_LENGTH       0x74
101*4882a593Smuzhiyun #define SAA7127_REG_CSYNC_ADVANCE_VSYNC_SHIFT        0x75
102*4882a593Smuzhiyun #define SAA7127_REG_TTX_ODD_REQ_VERT_START           0x76
103*4882a593Smuzhiyun #define SAA7127_REG_TTX_ODD_REQ_VERT_END             0x77
104*4882a593Smuzhiyun #define SAA7127_REG_TTX_EVEN_REQ_VERT_START          0x78
105*4882a593Smuzhiyun #define SAA7127_REG_TTX_EVEN_REQ_VERT_END            0x79
106*4882a593Smuzhiyun #define SAA7127_REG_FIRST_ACTIVE                     0x7a
107*4882a593Smuzhiyun #define SAA7127_REG_LAST_ACTIVE                      0x7b
108*4882a593Smuzhiyun #define SAA7127_REG_MSB_VERTICAL                     0x7c
109*4882a593Smuzhiyun #define SAA7127_REG_DISABLE_TTX_LINE_LO_0            0x7e
110*4882a593Smuzhiyun #define SAA7127_REG_DISABLE_TTX_LINE_LO_1            0x7f
111*4882a593Smuzhiyun 
112*4882a593Smuzhiyun /*
113*4882a593Smuzhiyun  **********************************************************************
114*4882a593Smuzhiyun  *
115*4882a593Smuzhiyun  *  Arrays with configuration parameters for the SAA7127
116*4882a593Smuzhiyun  *
117*4882a593Smuzhiyun  **********************************************************************
118*4882a593Smuzhiyun  */
119*4882a593Smuzhiyun 
120*4882a593Smuzhiyun struct i2c_reg_value {
121*4882a593Smuzhiyun 	unsigned char reg;
122*4882a593Smuzhiyun 	unsigned char value;
123*4882a593Smuzhiyun };
124*4882a593Smuzhiyun 
125*4882a593Smuzhiyun static const struct i2c_reg_value saa7129_init_config_extra[] = {
126*4882a593Smuzhiyun 	{ SAA7127_REG_OUTPUT_PORT_CONTROL,		0x38 },
127*4882a593Smuzhiyun 	{ SAA7127_REG_VTRIG,				0xfa },
128*4882a593Smuzhiyun 	{ 0, 0 }
129*4882a593Smuzhiyun };
130*4882a593Smuzhiyun 
131*4882a593Smuzhiyun static const struct i2c_reg_value saa7127_init_config_common[] = {
132*4882a593Smuzhiyun 	{ SAA7127_REG_WIDESCREEN_CONFIG,		0x0d },
133*4882a593Smuzhiyun 	{ SAA7127_REG_WIDESCREEN_ENABLE,		0x00 },
134*4882a593Smuzhiyun 	{ SAA7127_REG_COPYGEN_0,			0x77 },
135*4882a593Smuzhiyun 	{ SAA7127_REG_COPYGEN_1,			0x41 },
136*4882a593Smuzhiyun 	{ SAA7127_REG_COPYGEN_2,			0x00 },	/* Macrovision enable/disable */
137*4882a593Smuzhiyun 	{ SAA7127_REG_OUTPUT_PORT_CONTROL,		0xbf },
138*4882a593Smuzhiyun 	{ SAA7127_REG_GAIN_LUMINANCE_RGB,		0x00 },
139*4882a593Smuzhiyun 	{ SAA7127_REG_GAIN_COLORDIFF_RGB,		0x00 },
140*4882a593Smuzhiyun 	{ SAA7127_REG_INPUT_PORT_CONTROL_1,		0x80 },	/* for color bars */
141*4882a593Smuzhiyun 	{ SAA7127_REG_LINE_21_ODD_0,			0x77 },
142*4882a593Smuzhiyun 	{ SAA7127_REG_LINE_21_ODD_1,			0x41 },
143*4882a593Smuzhiyun 	{ SAA7127_REG_LINE_21_EVEN_0,			0x88 },
144*4882a593Smuzhiyun 	{ SAA7127_REG_LINE_21_EVEN_1,			0x41 },
145*4882a593Smuzhiyun 	{ SAA7127_REG_RCV_PORT_CONTROL,			0x12 },
146*4882a593Smuzhiyun 	{ SAA7127_REG_VTRIG,				0xf9 },
147*4882a593Smuzhiyun 	{ SAA7127_REG_HTRIG_HI,				0x00 },
148*4882a593Smuzhiyun 	{ SAA7127_REG_RCV2_OUTPUT_START,		0x41 },
149*4882a593Smuzhiyun 	{ SAA7127_REG_RCV2_OUTPUT_END,			0xc3 },
150*4882a593Smuzhiyun 	{ SAA7127_REG_RCV2_OUTPUT_MSBS,			0x00 },
151*4882a593Smuzhiyun 	{ SAA7127_REG_TTX_REQUEST_H_START,		0x3e },
152*4882a593Smuzhiyun 	{ SAA7127_REG_TTX_REQUEST_H_DELAY_LENGTH,	0xb8 },
153*4882a593Smuzhiyun 	{ SAA7127_REG_CSYNC_ADVANCE_VSYNC_SHIFT,	0x03 },
154*4882a593Smuzhiyun 	{ SAA7127_REG_TTX_ODD_REQ_VERT_START,		0x15 },
155*4882a593Smuzhiyun 	{ SAA7127_REG_TTX_ODD_REQ_VERT_END,		0x16 },
156*4882a593Smuzhiyun 	{ SAA7127_REG_TTX_EVEN_REQ_VERT_START,		0x15 },
157*4882a593Smuzhiyun 	{ SAA7127_REG_TTX_EVEN_REQ_VERT_END,		0x16 },
158*4882a593Smuzhiyun 	{ SAA7127_REG_FIRST_ACTIVE,			0x1a },
159*4882a593Smuzhiyun 	{ SAA7127_REG_LAST_ACTIVE,			0x01 },
160*4882a593Smuzhiyun 	{ SAA7127_REG_MSB_VERTICAL,			0xc0 },
161*4882a593Smuzhiyun 	{ SAA7127_REG_DISABLE_TTX_LINE_LO_0,		0x00 },
162*4882a593Smuzhiyun 	{ SAA7127_REG_DISABLE_TTX_LINE_LO_1,		0x00 },
163*4882a593Smuzhiyun 	{ 0, 0 }
164*4882a593Smuzhiyun };
165*4882a593Smuzhiyun 
166*4882a593Smuzhiyun #define SAA7127_60HZ_DAC_CONTROL 0x15
167*4882a593Smuzhiyun static const struct i2c_reg_value saa7127_init_config_60hz[] = {
168*4882a593Smuzhiyun 	{ SAA7127_REG_BURST_START,			0x19 },
169*4882a593Smuzhiyun 	/* BURST_END is also used as a chip ID in saa7127_probe */
170*4882a593Smuzhiyun 	{ SAA7127_REG_BURST_END,			0x1d },
171*4882a593Smuzhiyun 	{ SAA7127_REG_CHROMA_PHASE,			0xa3 },
172*4882a593Smuzhiyun 	{ SAA7127_REG_GAINU,				0x98 },
173*4882a593Smuzhiyun 	{ SAA7127_REG_GAINV,				0xd3 },
174*4882a593Smuzhiyun 	{ SAA7127_REG_BLACK_LEVEL,			0x39 },
175*4882a593Smuzhiyun 	{ SAA7127_REG_BLANKING_LEVEL,			0x2e },
176*4882a593Smuzhiyun 	{ SAA7127_REG_VBI_BLANKING,			0x2e },
177*4882a593Smuzhiyun 	{ SAA7127_REG_DAC_CONTROL,			0x15 },
178*4882a593Smuzhiyun 	{ SAA7127_REG_BURST_AMP,			0x4d },
179*4882a593Smuzhiyun 	{ SAA7127_REG_SUBC3,				0x1f },
180*4882a593Smuzhiyun 	{ SAA7127_REG_SUBC2,				0x7c },
181*4882a593Smuzhiyun 	{ SAA7127_REG_SUBC1,				0xf0 },
182*4882a593Smuzhiyun 	{ SAA7127_REG_SUBC0,				0x21 },
183*4882a593Smuzhiyun 	{ SAA7127_REG_MULTI,				0x90 },
184*4882a593Smuzhiyun 	{ SAA7127_REG_CLOSED_CAPTION,			0x11 },
185*4882a593Smuzhiyun 	{ 0, 0 }
186*4882a593Smuzhiyun };
187*4882a593Smuzhiyun 
188*4882a593Smuzhiyun #define SAA7127_50HZ_PAL_DAC_CONTROL 0x02
189*4882a593Smuzhiyun static struct i2c_reg_value saa7127_init_config_50hz_pal[] = {
190*4882a593Smuzhiyun 	{ SAA7127_REG_BURST_START,			0x21 },
191*4882a593Smuzhiyun 	/* BURST_END is also used as a chip ID in saa7127_probe */
192*4882a593Smuzhiyun 	{ SAA7127_REG_BURST_END,			0x1d },
193*4882a593Smuzhiyun 	{ SAA7127_REG_CHROMA_PHASE,			0x3f },
194*4882a593Smuzhiyun 	{ SAA7127_REG_GAINU,				0x7d },
195*4882a593Smuzhiyun 	{ SAA7127_REG_GAINV,				0xaf },
196*4882a593Smuzhiyun 	{ SAA7127_REG_BLACK_LEVEL,			0x33 },
197*4882a593Smuzhiyun 	{ SAA7127_REG_BLANKING_LEVEL,			0x35 },
198*4882a593Smuzhiyun 	{ SAA7127_REG_VBI_BLANKING,			0x35 },
199*4882a593Smuzhiyun 	{ SAA7127_REG_DAC_CONTROL,			0x02 },
200*4882a593Smuzhiyun 	{ SAA7127_REG_BURST_AMP,			0x2f },
201*4882a593Smuzhiyun 	{ SAA7127_REG_SUBC3,				0xcb },
202*4882a593Smuzhiyun 	{ SAA7127_REG_SUBC2,				0x8a },
203*4882a593Smuzhiyun 	{ SAA7127_REG_SUBC1,				0x09 },
204*4882a593Smuzhiyun 	{ SAA7127_REG_SUBC0,				0x2a },
205*4882a593Smuzhiyun 	{ SAA7127_REG_MULTI,				0xa0 },
206*4882a593Smuzhiyun 	{ SAA7127_REG_CLOSED_CAPTION,			0x00 },
207*4882a593Smuzhiyun 	{ 0, 0 }
208*4882a593Smuzhiyun };
209*4882a593Smuzhiyun 
210*4882a593Smuzhiyun #define SAA7127_50HZ_SECAM_DAC_CONTROL 0x08
211*4882a593Smuzhiyun static struct i2c_reg_value saa7127_init_config_50hz_secam[] = {
212*4882a593Smuzhiyun 	{ SAA7127_REG_BURST_START,			0x21 },
213*4882a593Smuzhiyun 	/* BURST_END is also used as a chip ID in saa7127_probe */
214*4882a593Smuzhiyun 	{ SAA7127_REG_BURST_END,			0x1d },
215*4882a593Smuzhiyun 	{ SAA7127_REG_CHROMA_PHASE,			0x3f },
216*4882a593Smuzhiyun 	{ SAA7127_REG_GAINU,				0x6a },
217*4882a593Smuzhiyun 	{ SAA7127_REG_GAINV,				0x81 },
218*4882a593Smuzhiyun 	{ SAA7127_REG_BLACK_LEVEL,			0x33 },
219*4882a593Smuzhiyun 	{ SAA7127_REG_BLANKING_LEVEL,			0x35 },
220*4882a593Smuzhiyun 	{ SAA7127_REG_VBI_BLANKING,			0x35 },
221*4882a593Smuzhiyun 	{ SAA7127_REG_DAC_CONTROL,			0x08 },
222*4882a593Smuzhiyun 	{ SAA7127_REG_BURST_AMP,			0x2f },
223*4882a593Smuzhiyun 	{ SAA7127_REG_SUBC3,				0xb2 },
224*4882a593Smuzhiyun 	{ SAA7127_REG_SUBC2,				0x3b },
225*4882a593Smuzhiyun 	{ SAA7127_REG_SUBC1,				0xa3 },
226*4882a593Smuzhiyun 	{ SAA7127_REG_SUBC0,				0x28 },
227*4882a593Smuzhiyun 	{ SAA7127_REG_MULTI,				0x90 },
228*4882a593Smuzhiyun 	{ SAA7127_REG_CLOSED_CAPTION,			0x00 },
229*4882a593Smuzhiyun 	{ 0, 0 }
230*4882a593Smuzhiyun };
231*4882a593Smuzhiyun 
232*4882a593Smuzhiyun /*
233*4882a593Smuzhiyun  **********************************************************************
234*4882a593Smuzhiyun  *
235*4882a593Smuzhiyun  *  Encoder Struct, holds the configuration state of the encoder
236*4882a593Smuzhiyun  *
237*4882a593Smuzhiyun  **********************************************************************
238*4882a593Smuzhiyun  */
239*4882a593Smuzhiyun 
240*4882a593Smuzhiyun enum saa712x_model {
241*4882a593Smuzhiyun 	SAA7127,
242*4882a593Smuzhiyun 	SAA7129,
243*4882a593Smuzhiyun };
244*4882a593Smuzhiyun 
245*4882a593Smuzhiyun struct saa7127_state {
246*4882a593Smuzhiyun 	struct v4l2_subdev sd;
247*4882a593Smuzhiyun 	v4l2_std_id std;
248*4882a593Smuzhiyun 	enum saa712x_model ident;
249*4882a593Smuzhiyun 	enum saa7127_input_type input_type;
250*4882a593Smuzhiyun 	enum saa7127_output_type output_type;
251*4882a593Smuzhiyun 	int video_enable;
252*4882a593Smuzhiyun 	int wss_enable;
253*4882a593Smuzhiyun 	u16 wss_mode;
254*4882a593Smuzhiyun 	int cc_enable;
255*4882a593Smuzhiyun 	u16 cc_data;
256*4882a593Smuzhiyun 	int xds_enable;
257*4882a593Smuzhiyun 	u16 xds_data;
258*4882a593Smuzhiyun 	int vps_enable;
259*4882a593Smuzhiyun 	u8 vps_data[5];
260*4882a593Smuzhiyun 	u8 reg_2d;
261*4882a593Smuzhiyun 	u8 reg_3a;
262*4882a593Smuzhiyun 	u8 reg_3a_cb;   /* colorbar bit */
263*4882a593Smuzhiyun 	u8 reg_61;
264*4882a593Smuzhiyun };
265*4882a593Smuzhiyun 
to_state(struct v4l2_subdev * sd)266*4882a593Smuzhiyun static inline struct saa7127_state *to_state(struct v4l2_subdev *sd)
267*4882a593Smuzhiyun {
268*4882a593Smuzhiyun 	return container_of(sd, struct saa7127_state, sd);
269*4882a593Smuzhiyun }
270*4882a593Smuzhiyun 
271*4882a593Smuzhiyun static const char * const output_strs[] =
272*4882a593Smuzhiyun {
273*4882a593Smuzhiyun 	"S-Video + Composite",
274*4882a593Smuzhiyun 	"Composite",
275*4882a593Smuzhiyun 	"S-Video",
276*4882a593Smuzhiyun 	"RGB",
277*4882a593Smuzhiyun 	"YUV C",
278*4882a593Smuzhiyun 	"YUV V"
279*4882a593Smuzhiyun };
280*4882a593Smuzhiyun 
281*4882a593Smuzhiyun static const char * const wss_strs[] = {
282*4882a593Smuzhiyun 	"invalid",
283*4882a593Smuzhiyun 	"letterbox 14:9 center",
284*4882a593Smuzhiyun 	"letterbox 14:9 top",
285*4882a593Smuzhiyun 	"invalid",
286*4882a593Smuzhiyun 	"letterbox 16:9 top",
287*4882a593Smuzhiyun 	"invalid",
288*4882a593Smuzhiyun 	"invalid",
289*4882a593Smuzhiyun 	"16:9 full format anamorphic",
290*4882a593Smuzhiyun 	"4:3 full format",
291*4882a593Smuzhiyun 	"invalid",
292*4882a593Smuzhiyun 	"invalid",
293*4882a593Smuzhiyun 	"letterbox 16:9 center",
294*4882a593Smuzhiyun 	"invalid",
295*4882a593Smuzhiyun 	"letterbox >16:9 center",
296*4882a593Smuzhiyun 	"14:9 full format center",
297*4882a593Smuzhiyun 	"invalid",
298*4882a593Smuzhiyun };
299*4882a593Smuzhiyun 
300*4882a593Smuzhiyun /* ----------------------------------------------------------------------- */
301*4882a593Smuzhiyun 
saa7127_read(struct v4l2_subdev * sd,u8 reg)302*4882a593Smuzhiyun static int saa7127_read(struct v4l2_subdev *sd, u8 reg)
303*4882a593Smuzhiyun {
304*4882a593Smuzhiyun 	struct i2c_client *client = v4l2_get_subdevdata(sd);
305*4882a593Smuzhiyun 
306*4882a593Smuzhiyun 	return i2c_smbus_read_byte_data(client, reg);
307*4882a593Smuzhiyun }
308*4882a593Smuzhiyun 
309*4882a593Smuzhiyun /* ----------------------------------------------------------------------- */
310*4882a593Smuzhiyun 
saa7127_write(struct v4l2_subdev * sd,u8 reg,u8 val)311*4882a593Smuzhiyun static int saa7127_write(struct v4l2_subdev *sd, u8 reg, u8 val)
312*4882a593Smuzhiyun {
313*4882a593Smuzhiyun 	struct i2c_client *client = v4l2_get_subdevdata(sd);
314*4882a593Smuzhiyun 	int i;
315*4882a593Smuzhiyun 
316*4882a593Smuzhiyun 	for (i = 0; i < 3; i++) {
317*4882a593Smuzhiyun 		if (i2c_smbus_write_byte_data(client, reg, val) == 0)
318*4882a593Smuzhiyun 			return 0;
319*4882a593Smuzhiyun 	}
320*4882a593Smuzhiyun 	v4l2_err(sd, "I2C Write Problem\n");
321*4882a593Smuzhiyun 	return -1;
322*4882a593Smuzhiyun }
323*4882a593Smuzhiyun 
324*4882a593Smuzhiyun /* ----------------------------------------------------------------------- */
325*4882a593Smuzhiyun 
saa7127_write_inittab(struct v4l2_subdev * sd,const struct i2c_reg_value * regs)326*4882a593Smuzhiyun static int saa7127_write_inittab(struct v4l2_subdev *sd,
327*4882a593Smuzhiyun 				 const struct i2c_reg_value *regs)
328*4882a593Smuzhiyun {
329*4882a593Smuzhiyun 	while (regs->reg != 0) {
330*4882a593Smuzhiyun 		saa7127_write(sd, regs->reg, regs->value);
331*4882a593Smuzhiyun 		regs++;
332*4882a593Smuzhiyun 	}
333*4882a593Smuzhiyun 	return 0;
334*4882a593Smuzhiyun }
335*4882a593Smuzhiyun 
336*4882a593Smuzhiyun /* ----------------------------------------------------------------------- */
337*4882a593Smuzhiyun 
saa7127_set_vps(struct v4l2_subdev * sd,const struct v4l2_sliced_vbi_data * data)338*4882a593Smuzhiyun static int saa7127_set_vps(struct v4l2_subdev *sd, const struct v4l2_sliced_vbi_data *data)
339*4882a593Smuzhiyun {
340*4882a593Smuzhiyun 	struct saa7127_state *state = to_state(sd);
341*4882a593Smuzhiyun 	int enable = (data->line != 0);
342*4882a593Smuzhiyun 
343*4882a593Smuzhiyun 	if (enable && (data->field != 0 || data->line != 16))
344*4882a593Smuzhiyun 		return -EINVAL;
345*4882a593Smuzhiyun 	if (state->vps_enable != enable) {
346*4882a593Smuzhiyun 		v4l2_dbg(1, debug, sd, "Turn VPS Signal %s\n", enable ? "on" : "off");
347*4882a593Smuzhiyun 		saa7127_write(sd, 0x54, enable << 7);
348*4882a593Smuzhiyun 		state->vps_enable = enable;
349*4882a593Smuzhiyun 	}
350*4882a593Smuzhiyun 	if (!enable)
351*4882a593Smuzhiyun 		return 0;
352*4882a593Smuzhiyun 
353*4882a593Smuzhiyun 	state->vps_data[0] = data->data[2];
354*4882a593Smuzhiyun 	state->vps_data[1] = data->data[8];
355*4882a593Smuzhiyun 	state->vps_data[2] = data->data[9];
356*4882a593Smuzhiyun 	state->vps_data[3] = data->data[10];
357*4882a593Smuzhiyun 	state->vps_data[4] = data->data[11];
358*4882a593Smuzhiyun 	v4l2_dbg(1, debug, sd, "Set VPS data %*ph\n", 5, state->vps_data);
359*4882a593Smuzhiyun 	saa7127_write(sd, 0x55, state->vps_data[0]);
360*4882a593Smuzhiyun 	saa7127_write(sd, 0x56, state->vps_data[1]);
361*4882a593Smuzhiyun 	saa7127_write(sd, 0x57, state->vps_data[2]);
362*4882a593Smuzhiyun 	saa7127_write(sd, 0x58, state->vps_data[3]);
363*4882a593Smuzhiyun 	saa7127_write(sd, 0x59, state->vps_data[4]);
364*4882a593Smuzhiyun 	return 0;
365*4882a593Smuzhiyun }
366*4882a593Smuzhiyun 
367*4882a593Smuzhiyun /* ----------------------------------------------------------------------- */
368*4882a593Smuzhiyun 
saa7127_set_cc(struct v4l2_subdev * sd,const struct v4l2_sliced_vbi_data * data)369*4882a593Smuzhiyun static int saa7127_set_cc(struct v4l2_subdev *sd, const struct v4l2_sliced_vbi_data *data)
370*4882a593Smuzhiyun {
371*4882a593Smuzhiyun 	struct saa7127_state *state = to_state(sd);
372*4882a593Smuzhiyun 	u16 cc = data->data[1] << 8 | data->data[0];
373*4882a593Smuzhiyun 	int enable = (data->line != 0);
374*4882a593Smuzhiyun 
375*4882a593Smuzhiyun 	if (enable && (data->field != 0 || data->line != 21))
376*4882a593Smuzhiyun 		return -EINVAL;
377*4882a593Smuzhiyun 	if (state->cc_enable != enable) {
378*4882a593Smuzhiyun 		v4l2_dbg(1, debug, sd,
379*4882a593Smuzhiyun 			"Turn CC %s\n", enable ? "on" : "off");
380*4882a593Smuzhiyun 		saa7127_write(sd, SAA7127_REG_CLOSED_CAPTION,
381*4882a593Smuzhiyun 			(state->xds_enable << 7) | (enable << 6) | 0x11);
382*4882a593Smuzhiyun 		state->cc_enable = enable;
383*4882a593Smuzhiyun 	}
384*4882a593Smuzhiyun 	if (!enable)
385*4882a593Smuzhiyun 		return 0;
386*4882a593Smuzhiyun 
387*4882a593Smuzhiyun 	v4l2_dbg(2, debug, sd, "CC data: %04x\n", cc);
388*4882a593Smuzhiyun 	saa7127_write(sd, SAA7127_REG_LINE_21_ODD_0, cc & 0xff);
389*4882a593Smuzhiyun 	saa7127_write(sd, SAA7127_REG_LINE_21_ODD_1, cc >> 8);
390*4882a593Smuzhiyun 	state->cc_data = cc;
391*4882a593Smuzhiyun 	return 0;
392*4882a593Smuzhiyun }
393*4882a593Smuzhiyun 
394*4882a593Smuzhiyun /* ----------------------------------------------------------------------- */
395*4882a593Smuzhiyun 
saa7127_set_xds(struct v4l2_subdev * sd,const struct v4l2_sliced_vbi_data * data)396*4882a593Smuzhiyun static int saa7127_set_xds(struct v4l2_subdev *sd, const struct v4l2_sliced_vbi_data *data)
397*4882a593Smuzhiyun {
398*4882a593Smuzhiyun 	struct saa7127_state *state = to_state(sd);
399*4882a593Smuzhiyun 	u16 xds = data->data[1] << 8 | data->data[0];
400*4882a593Smuzhiyun 	int enable = (data->line != 0);
401*4882a593Smuzhiyun 
402*4882a593Smuzhiyun 	if (enable && (data->field != 1 || data->line != 21))
403*4882a593Smuzhiyun 		return -EINVAL;
404*4882a593Smuzhiyun 	if (state->xds_enable != enable) {
405*4882a593Smuzhiyun 		v4l2_dbg(1, debug, sd, "Turn XDS %s\n", enable ? "on" : "off");
406*4882a593Smuzhiyun 		saa7127_write(sd, SAA7127_REG_CLOSED_CAPTION,
407*4882a593Smuzhiyun 				(enable << 7) | (state->cc_enable << 6) | 0x11);
408*4882a593Smuzhiyun 		state->xds_enable = enable;
409*4882a593Smuzhiyun 	}
410*4882a593Smuzhiyun 	if (!enable)
411*4882a593Smuzhiyun 		return 0;
412*4882a593Smuzhiyun 
413*4882a593Smuzhiyun 	v4l2_dbg(2, debug, sd, "XDS data: %04x\n", xds);
414*4882a593Smuzhiyun 	saa7127_write(sd, SAA7127_REG_LINE_21_EVEN_0, xds & 0xff);
415*4882a593Smuzhiyun 	saa7127_write(sd, SAA7127_REG_LINE_21_EVEN_1, xds >> 8);
416*4882a593Smuzhiyun 	state->xds_data = xds;
417*4882a593Smuzhiyun 	return 0;
418*4882a593Smuzhiyun }
419*4882a593Smuzhiyun 
420*4882a593Smuzhiyun /* ----------------------------------------------------------------------- */
421*4882a593Smuzhiyun 
saa7127_set_wss(struct v4l2_subdev * sd,const struct v4l2_sliced_vbi_data * data)422*4882a593Smuzhiyun static int saa7127_set_wss(struct v4l2_subdev *sd, const struct v4l2_sliced_vbi_data *data)
423*4882a593Smuzhiyun {
424*4882a593Smuzhiyun 	struct saa7127_state *state = to_state(sd);
425*4882a593Smuzhiyun 	int enable = (data->line != 0);
426*4882a593Smuzhiyun 
427*4882a593Smuzhiyun 	if (enable && (data->field != 0 || data->line != 23))
428*4882a593Smuzhiyun 		return -EINVAL;
429*4882a593Smuzhiyun 	if (state->wss_enable != enable) {
430*4882a593Smuzhiyun 		v4l2_dbg(1, debug, sd, "Turn WSS %s\n", enable ? "on" : "off");
431*4882a593Smuzhiyun 		saa7127_write(sd, 0x27, enable << 7);
432*4882a593Smuzhiyun 		state->wss_enable = enable;
433*4882a593Smuzhiyun 	}
434*4882a593Smuzhiyun 	if (!enable)
435*4882a593Smuzhiyun 		return 0;
436*4882a593Smuzhiyun 
437*4882a593Smuzhiyun 	saa7127_write(sd, 0x26, data->data[0]);
438*4882a593Smuzhiyun 	saa7127_write(sd, 0x27, 0x80 | (data->data[1] & 0x3f));
439*4882a593Smuzhiyun 	v4l2_dbg(1, debug, sd,
440*4882a593Smuzhiyun 		"WSS mode: %s\n", wss_strs[data->data[0] & 0xf]);
441*4882a593Smuzhiyun 	state->wss_mode = (data->data[1] & 0x3f) << 8 | data->data[0];
442*4882a593Smuzhiyun 	return 0;
443*4882a593Smuzhiyun }
444*4882a593Smuzhiyun 
445*4882a593Smuzhiyun /* ----------------------------------------------------------------------- */
446*4882a593Smuzhiyun 
saa7127_set_video_enable(struct v4l2_subdev * sd,int enable)447*4882a593Smuzhiyun static int saa7127_set_video_enable(struct v4l2_subdev *sd, int enable)
448*4882a593Smuzhiyun {
449*4882a593Smuzhiyun 	struct saa7127_state *state = to_state(sd);
450*4882a593Smuzhiyun 
451*4882a593Smuzhiyun 	if (enable) {
452*4882a593Smuzhiyun 		v4l2_dbg(1, debug, sd, "Enable Video Output\n");
453*4882a593Smuzhiyun 		saa7127_write(sd, 0x2d, state->reg_2d);
454*4882a593Smuzhiyun 		saa7127_write(sd, 0x61, state->reg_61);
455*4882a593Smuzhiyun 	} else {
456*4882a593Smuzhiyun 		v4l2_dbg(1, debug, sd, "Disable Video Output\n");
457*4882a593Smuzhiyun 		saa7127_write(sd, 0x2d, (state->reg_2d & 0xf0));
458*4882a593Smuzhiyun 		saa7127_write(sd, 0x61, (state->reg_61 | 0xc0));
459*4882a593Smuzhiyun 	}
460*4882a593Smuzhiyun 	state->video_enable = enable;
461*4882a593Smuzhiyun 	return 0;
462*4882a593Smuzhiyun }
463*4882a593Smuzhiyun 
464*4882a593Smuzhiyun /* ----------------------------------------------------------------------- */
465*4882a593Smuzhiyun 
saa7127_set_std(struct v4l2_subdev * sd,v4l2_std_id std)466*4882a593Smuzhiyun static int saa7127_set_std(struct v4l2_subdev *sd, v4l2_std_id std)
467*4882a593Smuzhiyun {
468*4882a593Smuzhiyun 	struct saa7127_state *state = to_state(sd);
469*4882a593Smuzhiyun 	const struct i2c_reg_value *inittab;
470*4882a593Smuzhiyun 
471*4882a593Smuzhiyun 	if (std & V4L2_STD_525_60) {
472*4882a593Smuzhiyun 		v4l2_dbg(1, debug, sd, "Selecting 60 Hz video Standard\n");
473*4882a593Smuzhiyun 		inittab = saa7127_init_config_60hz;
474*4882a593Smuzhiyun 		state->reg_61 = SAA7127_60HZ_DAC_CONTROL;
475*4882a593Smuzhiyun 
476*4882a593Smuzhiyun 	} else if (state->ident == SAA7129 &&
477*4882a593Smuzhiyun 		   (std & V4L2_STD_SECAM) &&
478*4882a593Smuzhiyun 		   !(std & (V4L2_STD_625_50 & ~V4L2_STD_SECAM))) {
479*4882a593Smuzhiyun 
480*4882a593Smuzhiyun 		/* If and only if SECAM, with a SAA712[89] */
481*4882a593Smuzhiyun 		v4l2_dbg(1, debug, sd,
482*4882a593Smuzhiyun 			 "Selecting 50 Hz SECAM video Standard\n");
483*4882a593Smuzhiyun 		inittab = saa7127_init_config_50hz_secam;
484*4882a593Smuzhiyun 		state->reg_61 = SAA7127_50HZ_SECAM_DAC_CONTROL;
485*4882a593Smuzhiyun 
486*4882a593Smuzhiyun 	} else {
487*4882a593Smuzhiyun 		v4l2_dbg(1, debug, sd, "Selecting 50 Hz PAL video Standard\n");
488*4882a593Smuzhiyun 		inittab = saa7127_init_config_50hz_pal;
489*4882a593Smuzhiyun 		state->reg_61 = SAA7127_50HZ_PAL_DAC_CONTROL;
490*4882a593Smuzhiyun 	}
491*4882a593Smuzhiyun 
492*4882a593Smuzhiyun 	/* Write Table */
493*4882a593Smuzhiyun 	saa7127_write_inittab(sd, inittab);
494*4882a593Smuzhiyun 	state->std = std;
495*4882a593Smuzhiyun 	return 0;
496*4882a593Smuzhiyun }
497*4882a593Smuzhiyun 
498*4882a593Smuzhiyun /* ----------------------------------------------------------------------- */
499*4882a593Smuzhiyun 
saa7127_set_output_type(struct v4l2_subdev * sd,int output)500*4882a593Smuzhiyun static int saa7127_set_output_type(struct v4l2_subdev *sd, int output)
501*4882a593Smuzhiyun {
502*4882a593Smuzhiyun 	struct saa7127_state *state = to_state(sd);
503*4882a593Smuzhiyun 
504*4882a593Smuzhiyun 	switch (output) {
505*4882a593Smuzhiyun 	case SAA7127_OUTPUT_TYPE_RGB:
506*4882a593Smuzhiyun 		state->reg_2d = 0x0f;	/* RGB + CVBS (for sync) */
507*4882a593Smuzhiyun 		state->reg_3a = 0x13;	/* by default switch YUV to RGB-matrix on */
508*4882a593Smuzhiyun 		break;
509*4882a593Smuzhiyun 
510*4882a593Smuzhiyun 	case SAA7127_OUTPUT_TYPE_COMPOSITE:
511*4882a593Smuzhiyun 		if (state->ident == SAA7129)
512*4882a593Smuzhiyun 			state->reg_2d = 0x20;	/* CVBS only */
513*4882a593Smuzhiyun 		else
514*4882a593Smuzhiyun 			state->reg_2d = 0x08;	/* 00001000 CVBS only, RGB DAC's off (high impedance mode) */
515*4882a593Smuzhiyun 		state->reg_3a = 0x13;	/* by default switch YUV to RGB-matrix on */
516*4882a593Smuzhiyun 		break;
517*4882a593Smuzhiyun 
518*4882a593Smuzhiyun 	case SAA7127_OUTPUT_TYPE_SVIDEO:
519*4882a593Smuzhiyun 		if (state->ident == SAA7129)
520*4882a593Smuzhiyun 			state->reg_2d = 0x18;	/* Y + C */
521*4882a593Smuzhiyun 		else
522*4882a593Smuzhiyun 			state->reg_2d = 0xff;   /*11111111  croma -> R, luma -> CVBS + G + B */
523*4882a593Smuzhiyun 		state->reg_3a = 0x13;	/* by default switch YUV to RGB-matrix on */
524*4882a593Smuzhiyun 		break;
525*4882a593Smuzhiyun 
526*4882a593Smuzhiyun 	case SAA7127_OUTPUT_TYPE_YUV_V:
527*4882a593Smuzhiyun 		state->reg_2d = 0x4f;	/* reg 2D = 01001111, all DAC's on, RGB + VBS */
528*4882a593Smuzhiyun 		state->reg_3a = 0x0b;	/* reg 3A = 00001011, bypass RGB-matrix */
529*4882a593Smuzhiyun 		break;
530*4882a593Smuzhiyun 
531*4882a593Smuzhiyun 	case SAA7127_OUTPUT_TYPE_YUV_C:
532*4882a593Smuzhiyun 		state->reg_2d = 0x0f;	/* reg 2D = 00001111, all DAC's on, RGB + CVBS */
533*4882a593Smuzhiyun 		state->reg_3a = 0x0b;	/* reg 3A = 00001011, bypass RGB-matrix */
534*4882a593Smuzhiyun 		break;
535*4882a593Smuzhiyun 
536*4882a593Smuzhiyun 	case SAA7127_OUTPUT_TYPE_BOTH:
537*4882a593Smuzhiyun 		if (state->ident == SAA7129)
538*4882a593Smuzhiyun 			state->reg_2d = 0x38;
539*4882a593Smuzhiyun 		else
540*4882a593Smuzhiyun 			state->reg_2d = 0xbf;
541*4882a593Smuzhiyun 		state->reg_3a = 0x13;	/* by default switch YUV to RGB-matrix on */
542*4882a593Smuzhiyun 		break;
543*4882a593Smuzhiyun 
544*4882a593Smuzhiyun 	default:
545*4882a593Smuzhiyun 		return -EINVAL;
546*4882a593Smuzhiyun 	}
547*4882a593Smuzhiyun 	v4l2_dbg(1, debug, sd,
548*4882a593Smuzhiyun 		"Selecting %s output type\n", output_strs[output]);
549*4882a593Smuzhiyun 
550*4882a593Smuzhiyun 	/* Configure Encoder */
551*4882a593Smuzhiyun 	saa7127_write(sd, 0x2d, state->reg_2d);
552*4882a593Smuzhiyun 	saa7127_write(sd, 0x3a, state->reg_3a | state->reg_3a_cb);
553*4882a593Smuzhiyun 	state->output_type = output;
554*4882a593Smuzhiyun 	return 0;
555*4882a593Smuzhiyun }
556*4882a593Smuzhiyun 
557*4882a593Smuzhiyun /* ----------------------------------------------------------------------- */
558*4882a593Smuzhiyun 
saa7127_set_input_type(struct v4l2_subdev * sd,int input)559*4882a593Smuzhiyun static int saa7127_set_input_type(struct v4l2_subdev *sd, int input)
560*4882a593Smuzhiyun {
561*4882a593Smuzhiyun 	struct saa7127_state *state = to_state(sd);
562*4882a593Smuzhiyun 
563*4882a593Smuzhiyun 	switch (input) {
564*4882a593Smuzhiyun 	case SAA7127_INPUT_TYPE_NORMAL:	/* avia */
565*4882a593Smuzhiyun 		v4l2_dbg(1, debug, sd, "Selecting Normal Encoder Input\n");
566*4882a593Smuzhiyun 		state->reg_3a_cb = 0;
567*4882a593Smuzhiyun 		break;
568*4882a593Smuzhiyun 
569*4882a593Smuzhiyun 	case SAA7127_INPUT_TYPE_TEST_IMAGE:	/* color bar */
570*4882a593Smuzhiyun 		v4l2_dbg(1, debug, sd, "Selecting Color Bar generator\n");
571*4882a593Smuzhiyun 		state->reg_3a_cb = 0x80;
572*4882a593Smuzhiyun 		break;
573*4882a593Smuzhiyun 
574*4882a593Smuzhiyun 	default:
575*4882a593Smuzhiyun 		return -EINVAL;
576*4882a593Smuzhiyun 	}
577*4882a593Smuzhiyun 	saa7127_write(sd, 0x3a, state->reg_3a | state->reg_3a_cb);
578*4882a593Smuzhiyun 	state->input_type = input;
579*4882a593Smuzhiyun 	return 0;
580*4882a593Smuzhiyun }
581*4882a593Smuzhiyun 
582*4882a593Smuzhiyun /* ----------------------------------------------------------------------- */
583*4882a593Smuzhiyun 
saa7127_s_std_output(struct v4l2_subdev * sd,v4l2_std_id std)584*4882a593Smuzhiyun static int saa7127_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
585*4882a593Smuzhiyun {
586*4882a593Smuzhiyun 	struct saa7127_state *state = to_state(sd);
587*4882a593Smuzhiyun 
588*4882a593Smuzhiyun 	if (state->std == std)
589*4882a593Smuzhiyun 		return 0;
590*4882a593Smuzhiyun 	return saa7127_set_std(sd, std);
591*4882a593Smuzhiyun }
592*4882a593Smuzhiyun 
saa7127_s_routing(struct v4l2_subdev * sd,u32 input,u32 output,u32 config)593*4882a593Smuzhiyun static int saa7127_s_routing(struct v4l2_subdev *sd,
594*4882a593Smuzhiyun 			     u32 input, u32 output, u32 config)
595*4882a593Smuzhiyun {
596*4882a593Smuzhiyun 	struct saa7127_state *state = to_state(sd);
597*4882a593Smuzhiyun 	int rc = 0;
598*4882a593Smuzhiyun 
599*4882a593Smuzhiyun 	if (state->input_type != input)
600*4882a593Smuzhiyun 		rc = saa7127_set_input_type(sd, input);
601*4882a593Smuzhiyun 	if (rc == 0 && state->output_type != output)
602*4882a593Smuzhiyun 		rc = saa7127_set_output_type(sd, output);
603*4882a593Smuzhiyun 	return rc;
604*4882a593Smuzhiyun }
605*4882a593Smuzhiyun 
saa7127_s_stream(struct v4l2_subdev * sd,int enable)606*4882a593Smuzhiyun static int saa7127_s_stream(struct v4l2_subdev *sd, int enable)
607*4882a593Smuzhiyun {
608*4882a593Smuzhiyun 	struct saa7127_state *state = to_state(sd);
609*4882a593Smuzhiyun 
610*4882a593Smuzhiyun 	if (state->video_enable == enable)
611*4882a593Smuzhiyun 		return 0;
612*4882a593Smuzhiyun 	return saa7127_set_video_enable(sd, enable);
613*4882a593Smuzhiyun }
614*4882a593Smuzhiyun 
saa7127_g_sliced_fmt(struct v4l2_subdev * sd,struct v4l2_sliced_vbi_format * fmt)615*4882a593Smuzhiyun static int saa7127_g_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *fmt)
616*4882a593Smuzhiyun {
617*4882a593Smuzhiyun 	struct saa7127_state *state = to_state(sd);
618*4882a593Smuzhiyun 
619*4882a593Smuzhiyun 	memset(fmt->service_lines, 0, sizeof(fmt->service_lines));
620*4882a593Smuzhiyun 	if (state->vps_enable)
621*4882a593Smuzhiyun 		fmt->service_lines[0][16] = V4L2_SLICED_VPS;
622*4882a593Smuzhiyun 	if (state->wss_enable)
623*4882a593Smuzhiyun 		fmt->service_lines[0][23] = V4L2_SLICED_WSS_625;
624*4882a593Smuzhiyun 	if (state->cc_enable) {
625*4882a593Smuzhiyun 		fmt->service_lines[0][21] = V4L2_SLICED_CAPTION_525;
626*4882a593Smuzhiyun 		fmt->service_lines[1][21] = V4L2_SLICED_CAPTION_525;
627*4882a593Smuzhiyun 	}
628*4882a593Smuzhiyun 	fmt->service_set =
629*4882a593Smuzhiyun 		(state->vps_enable ? V4L2_SLICED_VPS : 0) |
630*4882a593Smuzhiyun 		(state->wss_enable ? V4L2_SLICED_WSS_625 : 0) |
631*4882a593Smuzhiyun 		(state->cc_enable ? V4L2_SLICED_CAPTION_525 : 0);
632*4882a593Smuzhiyun 	return 0;
633*4882a593Smuzhiyun }
634*4882a593Smuzhiyun 
saa7127_s_vbi_data(struct v4l2_subdev * sd,const struct v4l2_sliced_vbi_data * data)635*4882a593Smuzhiyun static int saa7127_s_vbi_data(struct v4l2_subdev *sd, const struct v4l2_sliced_vbi_data *data)
636*4882a593Smuzhiyun {
637*4882a593Smuzhiyun 	switch (data->id) {
638*4882a593Smuzhiyun 	case V4L2_SLICED_WSS_625:
639*4882a593Smuzhiyun 		return saa7127_set_wss(sd, data);
640*4882a593Smuzhiyun 	case V4L2_SLICED_VPS:
641*4882a593Smuzhiyun 		return saa7127_set_vps(sd, data);
642*4882a593Smuzhiyun 	case V4L2_SLICED_CAPTION_525:
643*4882a593Smuzhiyun 		if (data->field == 0)
644*4882a593Smuzhiyun 			return saa7127_set_cc(sd, data);
645*4882a593Smuzhiyun 		return saa7127_set_xds(sd, data);
646*4882a593Smuzhiyun 	default:
647*4882a593Smuzhiyun 		return -EINVAL;
648*4882a593Smuzhiyun 	}
649*4882a593Smuzhiyun 	return 0;
650*4882a593Smuzhiyun }
651*4882a593Smuzhiyun 
652*4882a593Smuzhiyun #ifdef CONFIG_VIDEO_ADV_DEBUG
saa7127_g_register(struct v4l2_subdev * sd,struct v4l2_dbg_register * reg)653*4882a593Smuzhiyun static int saa7127_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
654*4882a593Smuzhiyun {
655*4882a593Smuzhiyun 	reg->val = saa7127_read(sd, reg->reg & 0xff);
656*4882a593Smuzhiyun 	reg->size = 1;
657*4882a593Smuzhiyun 	return 0;
658*4882a593Smuzhiyun }
659*4882a593Smuzhiyun 
saa7127_s_register(struct v4l2_subdev * sd,const struct v4l2_dbg_register * reg)660*4882a593Smuzhiyun static int saa7127_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg)
661*4882a593Smuzhiyun {
662*4882a593Smuzhiyun 	saa7127_write(sd, reg->reg & 0xff, reg->val & 0xff);
663*4882a593Smuzhiyun 	return 0;
664*4882a593Smuzhiyun }
665*4882a593Smuzhiyun #endif
666*4882a593Smuzhiyun 
saa7127_log_status(struct v4l2_subdev * sd)667*4882a593Smuzhiyun static int saa7127_log_status(struct v4l2_subdev *sd)
668*4882a593Smuzhiyun {
669*4882a593Smuzhiyun 	struct saa7127_state *state = to_state(sd);
670*4882a593Smuzhiyun 
671*4882a593Smuzhiyun 	v4l2_info(sd, "Standard: %s\n", (state->std & V4L2_STD_525_60) ? "60 Hz" : "50 Hz");
672*4882a593Smuzhiyun 	v4l2_info(sd, "Input:    %s\n", state->input_type ?  "color bars" : "normal");
673*4882a593Smuzhiyun 	v4l2_info(sd, "Output:   %s\n", state->video_enable ?
674*4882a593Smuzhiyun 			output_strs[state->output_type] : "disabled");
675*4882a593Smuzhiyun 	v4l2_info(sd, "WSS:      %s\n", state->wss_enable ?
676*4882a593Smuzhiyun 			wss_strs[state->wss_mode] : "disabled");
677*4882a593Smuzhiyun 	v4l2_info(sd, "VPS:      %s\n", state->vps_enable ? "enabled" : "disabled");
678*4882a593Smuzhiyun 	v4l2_info(sd, "CC:       %s\n", state->cc_enable ? "enabled" : "disabled");
679*4882a593Smuzhiyun 	return 0;
680*4882a593Smuzhiyun }
681*4882a593Smuzhiyun 
682*4882a593Smuzhiyun /* ----------------------------------------------------------------------- */
683*4882a593Smuzhiyun 
684*4882a593Smuzhiyun static const struct v4l2_subdev_core_ops saa7127_core_ops = {
685*4882a593Smuzhiyun 	.log_status = saa7127_log_status,
686*4882a593Smuzhiyun #ifdef CONFIG_VIDEO_ADV_DEBUG
687*4882a593Smuzhiyun 	.g_register = saa7127_g_register,
688*4882a593Smuzhiyun 	.s_register = saa7127_s_register,
689*4882a593Smuzhiyun #endif
690*4882a593Smuzhiyun };
691*4882a593Smuzhiyun 
692*4882a593Smuzhiyun static const struct v4l2_subdev_video_ops saa7127_video_ops = {
693*4882a593Smuzhiyun 	.s_std_output = saa7127_s_std_output,
694*4882a593Smuzhiyun 	.s_routing = saa7127_s_routing,
695*4882a593Smuzhiyun 	.s_stream = saa7127_s_stream,
696*4882a593Smuzhiyun };
697*4882a593Smuzhiyun 
698*4882a593Smuzhiyun static const struct v4l2_subdev_vbi_ops saa7127_vbi_ops = {
699*4882a593Smuzhiyun 	.s_vbi_data = saa7127_s_vbi_data,
700*4882a593Smuzhiyun 	.g_sliced_fmt = saa7127_g_sliced_fmt,
701*4882a593Smuzhiyun };
702*4882a593Smuzhiyun 
703*4882a593Smuzhiyun static const struct v4l2_subdev_ops saa7127_ops = {
704*4882a593Smuzhiyun 	.core = &saa7127_core_ops,
705*4882a593Smuzhiyun 	.video = &saa7127_video_ops,
706*4882a593Smuzhiyun 	.vbi = &saa7127_vbi_ops,
707*4882a593Smuzhiyun };
708*4882a593Smuzhiyun 
709*4882a593Smuzhiyun /* ----------------------------------------------------------------------- */
710*4882a593Smuzhiyun 
saa7127_probe(struct i2c_client * client,const struct i2c_device_id * id)711*4882a593Smuzhiyun static int saa7127_probe(struct i2c_client *client,
712*4882a593Smuzhiyun 			 const struct i2c_device_id *id)
713*4882a593Smuzhiyun {
714*4882a593Smuzhiyun 	struct saa7127_state *state;
715*4882a593Smuzhiyun 	struct v4l2_subdev *sd;
716*4882a593Smuzhiyun 	struct v4l2_sliced_vbi_data vbi = { 0, 0, 0, 0 };  /* set to disabled */
717*4882a593Smuzhiyun 
718*4882a593Smuzhiyun 	/* Check if the adapter supports the needed features */
719*4882a593Smuzhiyun 	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
720*4882a593Smuzhiyun 		return -EIO;
721*4882a593Smuzhiyun 
722*4882a593Smuzhiyun 	v4l_dbg(1, debug, client, "detecting saa7127 client on address 0x%x\n",
723*4882a593Smuzhiyun 			client->addr << 1);
724*4882a593Smuzhiyun 
725*4882a593Smuzhiyun 	state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL);
726*4882a593Smuzhiyun 	if (state == NULL)
727*4882a593Smuzhiyun 		return -ENOMEM;
728*4882a593Smuzhiyun 
729*4882a593Smuzhiyun 	sd = &state->sd;
730*4882a593Smuzhiyun 	v4l2_i2c_subdev_init(sd, client, &saa7127_ops);
731*4882a593Smuzhiyun 
732*4882a593Smuzhiyun 	/* First test register 0: Bits 5-7 are a version ID (should be 0),
733*4882a593Smuzhiyun 	   and bit 2 should also be 0.
734*4882a593Smuzhiyun 	   This is rather general, so the second test is more specific and
735*4882a593Smuzhiyun 	   looks at the 'ending point of burst in clock cycles' which is
736*4882a593Smuzhiyun 	   0x1d after a reset and not expected to ever change. */
737*4882a593Smuzhiyun 	if ((saa7127_read(sd, 0) & 0xe4) != 0 ||
738*4882a593Smuzhiyun 			(saa7127_read(sd, 0x29) & 0x3f) != 0x1d) {
739*4882a593Smuzhiyun 		v4l2_dbg(1, debug, sd, "saa7127 not found\n");
740*4882a593Smuzhiyun 		return -ENODEV;
741*4882a593Smuzhiyun 	}
742*4882a593Smuzhiyun 
743*4882a593Smuzhiyun 	if (id->driver_data) {	/* Chip type is already known */
744*4882a593Smuzhiyun 		state->ident = id->driver_data;
745*4882a593Smuzhiyun 	} else {		/* Needs detection */
746*4882a593Smuzhiyun 		int read_result;
747*4882a593Smuzhiyun 
748*4882a593Smuzhiyun 		/* Detect if it's an saa7129 */
749*4882a593Smuzhiyun 		read_result = saa7127_read(sd, SAA7129_REG_FADE_KEY_COL2);
750*4882a593Smuzhiyun 		saa7127_write(sd, SAA7129_REG_FADE_KEY_COL2, 0xaa);
751*4882a593Smuzhiyun 		if (saa7127_read(sd, SAA7129_REG_FADE_KEY_COL2) == 0xaa) {
752*4882a593Smuzhiyun 			saa7127_write(sd, SAA7129_REG_FADE_KEY_COL2,
753*4882a593Smuzhiyun 					read_result);
754*4882a593Smuzhiyun 			state->ident = SAA7129;
755*4882a593Smuzhiyun 			strscpy(client->name, "saa7129", I2C_NAME_SIZE);
756*4882a593Smuzhiyun 		} else {
757*4882a593Smuzhiyun 			state->ident = SAA7127;
758*4882a593Smuzhiyun 			strscpy(client->name, "saa7127", I2C_NAME_SIZE);
759*4882a593Smuzhiyun 		}
760*4882a593Smuzhiyun 	}
761*4882a593Smuzhiyun 
762*4882a593Smuzhiyun 	v4l2_info(sd, "%s found @ 0x%x (%s)\n", client->name,
763*4882a593Smuzhiyun 			client->addr << 1, client->adapter->name);
764*4882a593Smuzhiyun 
765*4882a593Smuzhiyun 	v4l2_dbg(1, debug, sd, "Configuring encoder\n");
766*4882a593Smuzhiyun 	saa7127_write_inittab(sd, saa7127_init_config_common);
767*4882a593Smuzhiyun 	saa7127_set_std(sd, V4L2_STD_NTSC);
768*4882a593Smuzhiyun 	saa7127_set_output_type(sd, SAA7127_OUTPUT_TYPE_BOTH);
769*4882a593Smuzhiyun 	saa7127_set_vps(sd, &vbi);
770*4882a593Smuzhiyun 	saa7127_set_wss(sd, &vbi);
771*4882a593Smuzhiyun 	saa7127_set_cc(sd, &vbi);
772*4882a593Smuzhiyun 	saa7127_set_xds(sd, &vbi);
773*4882a593Smuzhiyun 	if (test_image == 1)
774*4882a593Smuzhiyun 		/* The Encoder has an internal Colorbar generator */
775*4882a593Smuzhiyun 		/* This can be used for debugging */
776*4882a593Smuzhiyun 		saa7127_set_input_type(sd, SAA7127_INPUT_TYPE_TEST_IMAGE);
777*4882a593Smuzhiyun 	else
778*4882a593Smuzhiyun 		saa7127_set_input_type(sd, SAA7127_INPUT_TYPE_NORMAL);
779*4882a593Smuzhiyun 	saa7127_set_video_enable(sd, 1);
780*4882a593Smuzhiyun 
781*4882a593Smuzhiyun 	if (state->ident == SAA7129)
782*4882a593Smuzhiyun 		saa7127_write_inittab(sd, saa7129_init_config_extra);
783*4882a593Smuzhiyun 	return 0;
784*4882a593Smuzhiyun }
785*4882a593Smuzhiyun 
786*4882a593Smuzhiyun /* ----------------------------------------------------------------------- */
787*4882a593Smuzhiyun 
saa7127_remove(struct i2c_client * client)788*4882a593Smuzhiyun static int saa7127_remove(struct i2c_client *client)
789*4882a593Smuzhiyun {
790*4882a593Smuzhiyun 	struct v4l2_subdev *sd = i2c_get_clientdata(client);
791*4882a593Smuzhiyun 
792*4882a593Smuzhiyun 	v4l2_device_unregister_subdev(sd);
793*4882a593Smuzhiyun 	/* Turn off TV output */
794*4882a593Smuzhiyun 	saa7127_set_video_enable(sd, 0);
795*4882a593Smuzhiyun 	return 0;
796*4882a593Smuzhiyun }
797*4882a593Smuzhiyun 
798*4882a593Smuzhiyun /* ----------------------------------------------------------------------- */
799*4882a593Smuzhiyun 
800*4882a593Smuzhiyun static const struct i2c_device_id saa7127_id[] = {
801*4882a593Smuzhiyun 	{ "saa7127_auto", 0 },	/* auto-detection */
802*4882a593Smuzhiyun 	{ "saa7126", SAA7127 },
803*4882a593Smuzhiyun 	{ "saa7127", SAA7127 },
804*4882a593Smuzhiyun 	{ "saa7128", SAA7129 },
805*4882a593Smuzhiyun 	{ "saa7129", SAA7129 },
806*4882a593Smuzhiyun 	{ }
807*4882a593Smuzhiyun };
808*4882a593Smuzhiyun MODULE_DEVICE_TABLE(i2c, saa7127_id);
809*4882a593Smuzhiyun 
810*4882a593Smuzhiyun static struct i2c_driver saa7127_driver = {
811*4882a593Smuzhiyun 	.driver = {
812*4882a593Smuzhiyun 		.name	= "saa7127",
813*4882a593Smuzhiyun 	},
814*4882a593Smuzhiyun 	.probe		= saa7127_probe,
815*4882a593Smuzhiyun 	.remove		= saa7127_remove,
816*4882a593Smuzhiyun 	.id_table	= saa7127_id,
817*4882a593Smuzhiyun };
818*4882a593Smuzhiyun 
819*4882a593Smuzhiyun module_i2c_driver(saa7127_driver);
820