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