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