blob: ca725a74ce6a7f0600e88d20ff467a085a7212e9 [file] [log] [blame]
Hans Verkuile281db582008-08-08 12:43:59 -03001 /*
2 saa6752hs - i2c-driver for the saa6752hs by Philips
3
4 Copyright (C) 2004 Andrew de Quincey
5
6 AC-3 support:
7
8 Copyright (C) 2008 Hans Verkuil <hverkuil@xs4all.nl>
9
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License vs published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 675 Mvss Ave, Cambridge, MA 02139, USA.
23 */
24
Linus Torvalds1da177e2005-04-16 15:20:36 -070025#include <linux/module.h>
26#include <linux/kernel.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070027#include <linux/string.h>
28#include <linux/timer.h>
29#include <linux/delay.h>
30#include <linux/errno.h>
31#include <linux/slab.h>
32#include <linux/poll.h>
33#include <linux/i2c.h>
34#include <linux/types.h>
Mauro Carvalho Chehabcab462f2006-01-09 15:53:26 -020035#include <linux/videodev2.h>
36#include <media/v4l2-common.h>
Hans Verkuile281db582008-08-08 12:43:59 -030037#include <media/v4l2-chip-ident.h>
38#include <media/v4l2-i2c-drv-legacy.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070039#include <linux/init.h>
40#include <linux/crc32.h>
41
Linus Torvalds1da177e2005-04-16 15:20:36 -070042#define MPEG_VIDEO_TARGET_BITRATE_MAX 27000
43#define MPEG_VIDEO_MAX_BITRATE_MAX 27000
44#define MPEG_TOTAL_TARGET_BITRATE_MAX 27000
45#define MPEG_PID_MAX ((1 << 14) - 1)
46
47/* Addresses to scan */
48static unsigned short normal_i2c[] = {0x20, I2C_CLIENT_END};
Hans Verkuilf87086e2008-07-18 00:50:58 -030049
Linus Torvalds1da177e2005-04-16 15:20:36 -070050I2C_CLIENT_INSMOD;
51
52MODULE_DESCRIPTION("device driver for saa6752hs MPEG2 encoder");
53MODULE_AUTHOR("Andrew de Quincey");
54MODULE_LICENSE("GPL");
55
Frederic CAND0a4c9c92005-05-05 16:15:52 -070056enum saa6752hs_videoformat {
57 SAA6752HS_VF_D1 = 0, /* standard D1 video format: 720x576 */
58 SAA6752HS_VF_2_3_D1 = 1,/* 2/3D1 video format: 480x576 */
59 SAA6752HS_VF_1_2_D1 = 2,/* 1/2D1 video format: 352x576 */
60 SAA6752HS_VF_SIF = 3, /* SIF video format: 352x288 */
61 SAA6752HS_VF_UNKNOWN,
62};
63
Hans Verkuil86b79d62006-06-18 16:40:10 -030064struct saa6752hs_mpeg_params {
65 /* transport streams */
66 __u16 ts_pid_pmt;
67 __u16 ts_pid_audio;
68 __u16 ts_pid_video;
69 __u16 ts_pid_pcr;
70
71 /* audio */
Hans Verkuile281db582008-08-08 12:43:59 -030072 enum v4l2_mpeg_audio_encoding au_encoding;
73 enum v4l2_mpeg_audio_l2_bitrate au_l2_bitrate;
74 enum v4l2_mpeg_audio_ac3_bitrate au_ac3_bitrate;
Hans Verkuil86b79d62006-06-18 16:40:10 -030075
76 /* video */
77 enum v4l2_mpeg_video_aspect vi_aspect;
78 enum v4l2_mpeg_video_bitrate_mode vi_bitrate_mode;
79 __u32 vi_bitrate;
80 __u32 vi_bitrate_peak;
81};
82
Frederic CAND0a4c9c92005-05-05 16:15:52 -070083static const struct v4l2_format v4l2_format_table[] =
84{
Mauro Carvalho Chehabac19ecc2005-06-23 22:05:09 -070085 [SAA6752HS_VF_D1] =
86 { .fmt = { .pix = { .width = 720, .height = 576 }}},
87 [SAA6752HS_VF_2_3_D1] =
88 { .fmt = { .pix = { .width = 480, .height = 576 }}},
89 [SAA6752HS_VF_1_2_D1] =
90 { .fmt = { .pix = { .width = 352, .height = 576 }}},
91 [SAA6752HS_VF_SIF] =
92 { .fmt = { .pix = { .width = 352, .height = 288 }}},
93 [SAA6752HS_VF_UNKNOWN] =
94 { .fmt = { .pix = { .width = 0, .height = 0}}},
Frederic CAND0a4c9c92005-05-05 16:15:52 -070095};
96
Linus Torvalds1da177e2005-04-16 15:20:36 -070097struct saa6752hs_state {
Hans Verkuile281db582008-08-08 12:43:59 -030098 int chip;
99 u32 revision;
100 int has_ac3;
Hans Verkuil86b79d62006-06-18 16:40:10 -0300101 struct saa6752hs_mpeg_params params;
Frederic CAND0a4c9c92005-05-05 16:15:52 -0700102 enum saa6752hs_videoformat video_format;
Robert W. Boone9b715212005-11-08 21:36:45 -0800103 v4l2_std_id standard;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104};
105
106enum saa6752hs_command {
107 SAA6752HS_COMMAND_RESET = 0,
Trent Piepho657de3c2006-06-20 00:30:57 -0300108 SAA6752HS_COMMAND_STOP = 1,
109 SAA6752HS_COMMAND_START = 2,
110 SAA6752HS_COMMAND_PAUSE = 3,
111 SAA6752HS_COMMAND_RECONFIGURE = 4,
112 SAA6752HS_COMMAND_SLEEP = 5,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113 SAA6752HS_COMMAND_RECONFIGURE_FORCE = 6,
114
115 SAA6752HS_COMMAND_MAX
116};
117
118/* ---------------------------------------------------------------------- */
119
120static u8 PAT[] = {
Robert W. Boone9b715212005-11-08 21:36:45 -0800121 0xc2, /* i2c register */
122 0x00, /* table number for encoder */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123
Robert W. Boone9b715212005-11-08 21:36:45 -0800124 0x47, /* sync */
125 0x40, 0x00, /* transport_error_indicator(0), payload_unit_start(1), transport_priority(0), pid(0) */
126 0x10, /* transport_scrambling_control(00), adaptation_field_control(01), continuity_counter(0) */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127
Robert W. Boone9b715212005-11-08 21:36:45 -0800128 0x00, /* PSI pointer to start of table */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129
Robert W. Boone9b715212005-11-08 21:36:45 -0800130 0x00, /* tid(0) */
131 0xb0, 0x0d, /* section_syntax_indicator(1), section_length(13) */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132
Robert W. Boone9b715212005-11-08 21:36:45 -0800133 0x00, 0x01, /* transport_stream_id(1) */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134
Robert W. Boone9b715212005-11-08 21:36:45 -0800135 0xc1, /* version_number(0), current_next_indicator(1) */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136
Robert W. Boone9b715212005-11-08 21:36:45 -0800137 0x00, 0x00, /* section_number(0), last_section_number(0) */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138
Robert W. Boone9b715212005-11-08 21:36:45 -0800139 0x00, 0x01, /* program_number(1) */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140
Robert W. Boone9b715212005-11-08 21:36:45 -0800141 0xe0, 0x00, /* PMT PID */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142
Robert W. Boone9b715212005-11-08 21:36:45 -0800143 0x00, 0x00, 0x00, 0x00 /* CRC32 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144};
145
146static u8 PMT[] = {
Robert W. Boone9b715212005-11-08 21:36:45 -0800147 0xc2, /* i2c register */
148 0x01, /* table number for encoder */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149
Robert W. Boone9b715212005-11-08 21:36:45 -0800150 0x47, /* sync */
151 0x40, 0x00, /* transport_error_indicator(0), payload_unit_start(1), transport_priority(0), pid */
152 0x10, /* transport_scrambling_control(00), adaptation_field_control(01), continuity_counter(0) */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153
Robert W. Boone9b715212005-11-08 21:36:45 -0800154 0x00, /* PSI pointer to start of table */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155
Robert W. Boone9b715212005-11-08 21:36:45 -0800156 0x02, /* tid(2) */
157 0xb0, 0x17, /* section_syntax_indicator(1), section_length(23) */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158
Robert W. Boone9b715212005-11-08 21:36:45 -0800159 0x00, 0x01, /* program_number(1) */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160
Robert W. Boone9b715212005-11-08 21:36:45 -0800161 0xc1, /* version_number(0), current_next_indicator(1) */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162
Robert W. Boone9b715212005-11-08 21:36:45 -0800163 0x00, 0x00, /* section_number(0), last_section_number(0) */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164
Robert W. Boone9b715212005-11-08 21:36:45 -0800165 0xe0, 0x00, /* PCR_PID */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166
Robert W. Boone9b715212005-11-08 21:36:45 -0800167 0xf0, 0x00, /* program_info_length(0) */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168
Robert W. Boone9b715212005-11-08 21:36:45 -0800169 0x02, 0xe0, 0x00, 0xf0, 0x00, /* video stream type(2), pid */
170 0x04, 0xe0, 0x00, 0xf0, 0x00, /* audio stream type(4), pid */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171
Robert W. Boone9b715212005-11-08 21:36:45 -0800172 0x00, 0x00, 0x00, 0x00 /* CRC32 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173};
174
Hans Verkuil86b79d62006-06-18 16:40:10 -0300175static struct saa6752hs_mpeg_params param_defaults =
176{
177 .ts_pid_pmt = 16,
178 .ts_pid_video = 260,
179 .ts_pid_audio = 256,
180 .ts_pid_pcr = 259,
181
182 .vi_aspect = V4L2_MPEG_VIDEO_ASPECT_4x3,
183 .vi_bitrate = 4000,
184 .vi_bitrate_peak = 6000,
185 .vi_bitrate_mode = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
186
Hans Verkuile281db582008-08-08 12:43:59 -0300187 .au_encoding = V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
Hans Verkuil86b79d62006-06-18 16:40:10 -0300188 .au_l2_bitrate = V4L2_MPEG_AUDIO_L2_BITRATE_256K,
Hans Verkuile281db582008-08-08 12:43:59 -0300189 .au_ac3_bitrate = V4L2_MPEG_AUDIO_AC3_BITRATE_384K,
Hans Verkuil86b79d62006-06-18 16:40:10 -0300190};
191
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192/* ---------------------------------------------------------------------- */
193
194static int saa6752hs_chip_command(struct i2c_client* client,
195 enum saa6752hs_command command)
196{
197 unsigned char buf[3];
198 unsigned long timeout;
199 int status = 0;
200
Robert W. Boone9b715212005-11-08 21:36:45 -0800201 /* execute the command */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202 switch(command) {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800203 case SAA6752HS_COMMAND_RESET:
204 buf[0] = 0x00;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205 break;
206
207 case SAA6752HS_COMMAND_STOP:
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800208 buf[0] = 0x03;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209 break;
210
211 case SAA6752HS_COMMAND_START:
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800212 buf[0] = 0x02;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213 break;
214
215 case SAA6752HS_COMMAND_PAUSE:
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800216 buf[0] = 0x04;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217 break;
218
219 case SAA6752HS_COMMAND_RECONFIGURE:
220 buf[0] = 0x05;
221 break;
222
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800223 case SAA6752HS_COMMAND_SLEEP:
224 buf[0] = 0x06;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225 break;
226
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800227 case SAA6752HS_COMMAND_RECONFIGURE_FORCE:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228 buf[0] = 0x07;
229 break;
230
231 default:
232 return -EINVAL;
233 }
234
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800235 /* set it and wait for it to be so */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236 i2c_master_send(client, buf, 1);
237 timeout = jiffies + HZ * 3;
238 for (;;) {
Robert W. Boone9b715212005-11-08 21:36:45 -0800239 /* get the current status */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240 buf[0] = 0x10;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800241 i2c_master_send(client, buf, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242 i2c_master_recv(client, buf, 1);
243
244 if (!(buf[0] & 0x20))
245 break;
246 if (time_after(jiffies,timeout)) {
247 status = -ETIMEDOUT;
248 break;
249 }
250
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251 msleep(10);
252 }
253
Robert W. Boone9b715212005-11-08 21:36:45 -0800254 /* delay a bit to let encoder settle */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255 msleep(50);
256
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800257 return status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258}
259
260
261static int saa6752hs_set_bitrate(struct i2c_client* client,
Hans Verkuile281db582008-08-08 12:43:59 -0300262 struct saa6752hs_state *h)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263{
Hans Verkuile281db582008-08-08 12:43:59 -0300264 struct saa6752hs_mpeg_params *params = &h->params;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800265 u8 buf[3];
Mauro Carvalho Chehabb57e5572006-06-23 16:13:56 -0300266 int tot_bitrate;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267
Robert W. Boone9b715212005-11-08 21:36:45 -0800268 /* set the bitrate mode */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269 buf[0] = 0x71;
Mauro Carvalho Chehabb57e5572006-06-23 16:13:56 -0300270 buf[1] = (params->vi_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) ? 0 : 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271 i2c_master_send(client, buf, 2);
272
Robert W. Boone9b715212005-11-08 21:36:45 -0800273 /* set the video bitrate */
Mauro Carvalho Chehabb57e5572006-06-23 16:13:56 -0300274 if (params->vi_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) {
Robert W. Boone9b715212005-11-08 21:36:45 -0800275 /* set the target bitrate */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276 buf[0] = 0x80;
Mauro Carvalho Chehabb57e5572006-06-23 16:13:56 -0300277 buf[1] = params->vi_bitrate >> 8;
278 buf[2] = params->vi_bitrate & 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279 i2c_master_send(client, buf, 3);
280
Robert W. Boone9b715212005-11-08 21:36:45 -0800281 /* set the max bitrate */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282 buf[0] = 0x81;
Mauro Carvalho Chehabb57e5572006-06-23 16:13:56 -0300283 buf[1] = params->vi_bitrate_peak >> 8;
284 buf[2] = params->vi_bitrate_peak & 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285 i2c_master_send(client, buf, 3);
Mauro Carvalho Chehabb57e5572006-06-23 16:13:56 -0300286 tot_bitrate = params->vi_bitrate_peak;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287 } else {
Robert W. Boone9b715212005-11-08 21:36:45 -0800288 /* set the target bitrate (no max bitrate for CBR) */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800289 buf[0] = 0x81;
Mauro Carvalho Chehabb57e5572006-06-23 16:13:56 -0300290 buf[1] = params->vi_bitrate >> 8;
291 buf[2] = params->vi_bitrate & 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292 i2c_master_send(client, buf, 3);
Mauro Carvalho Chehabb57e5572006-06-23 16:13:56 -0300293 tot_bitrate = params->vi_bitrate;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294 }
295
Hans Verkuile281db582008-08-08 12:43:59 -0300296 /* set the audio encoding */
297 buf[0] = 0x93;
298 if (params->au_encoding == V4L2_MPEG_AUDIO_ENCODING_AC3)
299 buf[1] = 1;
300 else
301 buf[1] = 0;
302 i2c_master_send(client, buf, 2);
303
Robert W. Boone9b715212005-11-08 21:36:45 -0800304 /* set the audio bitrate */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800305 buf[0] = 0x94;
Hans Verkuile281db582008-08-08 12:43:59 -0300306 if (params->au_encoding == V4L2_MPEG_AUDIO_ENCODING_AC3)
307 buf[1] = V4L2_MPEG_AUDIO_AC3_BITRATE_384K == params->au_ac3_bitrate;
308 else
309 buf[1] = V4L2_MPEG_AUDIO_L2_BITRATE_384K == params->au_l2_bitrate;
310 tot_bitrate += buf[1] ? 384 : 256;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311 i2c_master_send(client, buf, 2);
Mauro Carvalho Chehabb57e5572006-06-23 16:13:56 -0300312
313 /* Note: the total max bitrate is determined by adding the video and audio
314 bitrates together and also adding an extra 768kbit/s to stay on the
315 safe side. If more control should be required, then an extra MPEG control
316 should be added. */
317 tot_bitrate += 768;
318 if (tot_bitrate > MPEG_TOTAL_TARGET_BITRATE_MAX)
319 tot_bitrate = MPEG_TOTAL_TARGET_BITRATE_MAX;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320
Robert W. Boone9b715212005-11-08 21:36:45 -0800321 /* set the total bitrate */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322 buf[0] = 0xb1;
Mauro Carvalho Chehabb57e5572006-06-23 16:13:56 -0300323 buf[1] = tot_bitrate >> 8;
324 buf[2] = tot_bitrate & 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325 i2c_master_send(client, buf, 3);
326
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327 return 0;
328}
329
Frederic CAND0a4c9c92005-05-05 16:15:52 -0700330static void saa6752hs_set_subsampling(struct i2c_client* client,
331 struct v4l2_format* f)
332{
333 struct saa6752hs_state *h = i2c_get_clientdata(client);
334 int dist_352, dist_480, dist_720;
335
336 /*
337 FIXME: translate and round width/height into EMPRESS
338 subsample type:
339
340 type | PAL | NTSC
341 ---------------------------
342 SIF | 352x288 | 352x240
343 1/2 D1 | 352x576 | 352x480
344 2/3 D1 | 480x576 | 480x480
345 D1 | 720x576 | 720x480
346 */
347
348 dist_352 = abs(f->fmt.pix.width - 352);
349 dist_480 = abs(f->fmt.pix.width - 480);
350 dist_720 = abs(f->fmt.pix.width - 720);
351 if (dist_720 < dist_480) {
352 f->fmt.pix.width = 720;
353 f->fmt.pix.height = 576;
354 h->video_format = SAA6752HS_VF_D1;
355 }
356 else if (dist_480 < dist_352) {
357 f->fmt.pix.width = 480;
358 f->fmt.pix.height = 576;
359 h->video_format = SAA6752HS_VF_2_3_D1;
360 }
361 else {
362 f->fmt.pix.width = 352;
363 if (abs(f->fmt.pix.height - 576) <
364 abs(f->fmt.pix.height - 288)) {
365 f->fmt.pix.height = 576;
366 h->video_format = SAA6752HS_VF_1_2_D1;
367 }
368 else {
369 f->fmt.pix.height = 288;
370 h->video_format = SAA6752HS_VF_SIF;
371 }
372 }
373}
374
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375
Hans Verkuile281db582008-08-08 12:43:59 -0300376static int handle_ctrl(int has_ac3, struct saa6752hs_mpeg_params *params,
Hans Verkuil4d6b5ae2006-06-26 09:31:18 -0300377 struct v4l2_ext_control *ctrl, unsigned int cmd)
Hans Verkuil86b79d62006-06-18 16:40:10 -0300378{
379 int old = 0, new;
Hans Verkuil4d6b5ae2006-06-26 09:31:18 -0300380 int set = (cmd == VIDIOC_S_EXT_CTRLS);
Hans Verkuil86b79d62006-06-18 16:40:10 -0300381
382 new = ctrl->value;
383 switch (ctrl->id) {
384 case V4L2_CID_MPEG_STREAM_TYPE:
385 old = V4L2_MPEG_STREAM_TYPE_MPEG2_TS;
386 if (set && new != old)
387 return -ERANGE;
388 new = old;
389 break;
390 case V4L2_CID_MPEG_STREAM_PID_PMT:
391 old = params->ts_pid_pmt;
392 if (set && new > MPEG_PID_MAX)
393 return -ERANGE;
394 if (new > MPEG_PID_MAX)
395 new = MPEG_PID_MAX;
396 params->ts_pid_pmt = new;
397 break;
398 case V4L2_CID_MPEG_STREAM_PID_AUDIO:
399 old = params->ts_pid_audio;
400 if (set && new > MPEG_PID_MAX)
401 return -ERANGE;
402 if (new > MPEG_PID_MAX)
403 new = MPEG_PID_MAX;
404 params->ts_pid_audio = new;
405 break;
406 case V4L2_CID_MPEG_STREAM_PID_VIDEO:
407 old = params->ts_pid_video;
408 if (set && new > MPEG_PID_MAX)
409 return -ERANGE;
410 if (new > MPEG_PID_MAX)
411 new = MPEG_PID_MAX;
412 params->ts_pid_video = new;
413 break;
414 case V4L2_CID_MPEG_STREAM_PID_PCR:
415 old = params->ts_pid_pcr;
416 if (set && new > MPEG_PID_MAX)
417 return -ERANGE;
418 if (new > MPEG_PID_MAX)
419 new = MPEG_PID_MAX;
420 params->ts_pid_pcr = new;
421 break;
422 case V4L2_CID_MPEG_AUDIO_ENCODING:
Hans Verkuile281db582008-08-08 12:43:59 -0300423 old = params->au_encoding;
424 if (set && new != V4L2_MPEG_AUDIO_ENCODING_LAYER_2 &&
425 (!has_ac3 || new != V4L2_MPEG_AUDIO_ENCODING_AC3))
Hans Verkuil86b79d62006-06-18 16:40:10 -0300426 return -ERANGE;
427 new = old;
428 break;
429 case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
430 old = params->au_l2_bitrate;
431 if (set && new != V4L2_MPEG_AUDIO_L2_BITRATE_256K &&
432 new != V4L2_MPEG_AUDIO_L2_BITRATE_384K)
433 return -ERANGE;
434 if (new <= V4L2_MPEG_AUDIO_L2_BITRATE_256K)
435 new = V4L2_MPEG_AUDIO_L2_BITRATE_256K;
436 else
437 new = V4L2_MPEG_AUDIO_L2_BITRATE_384K;
438 params->au_l2_bitrate = new;
439 break;
Hans Verkuile281db582008-08-08 12:43:59 -0300440 case V4L2_CID_MPEG_AUDIO_AC3_BITRATE:
441 if (!has_ac3)
442 return -EINVAL;
443 old = params->au_ac3_bitrate;
444 if (set && new != V4L2_MPEG_AUDIO_AC3_BITRATE_256K &&
445 new != V4L2_MPEG_AUDIO_AC3_BITRATE_384K)
446 return -ERANGE;
447 if (new <= V4L2_MPEG_AUDIO_AC3_BITRATE_256K)
448 new = V4L2_MPEG_AUDIO_AC3_BITRATE_256K;
449 else
450 new = V4L2_MPEG_AUDIO_AC3_BITRATE_384K;
451 params->au_ac3_bitrate = new;
452 break;
Hans Verkuil86b79d62006-06-18 16:40:10 -0300453 case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
454 old = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000;
455 if (set && new != old)
456 return -ERANGE;
457 new = old;
458 break;
459 case V4L2_CID_MPEG_VIDEO_ENCODING:
460 old = V4L2_MPEG_VIDEO_ENCODING_MPEG_2;
461 if (set && new != old)
462 return -ERANGE;
463 new = old;
464 break;
465 case V4L2_CID_MPEG_VIDEO_ASPECT:
466 old = params->vi_aspect;
467 if (set && new != V4L2_MPEG_VIDEO_ASPECT_16x9 &&
468 new != V4L2_MPEG_VIDEO_ASPECT_4x3)
469 return -ERANGE;
470 if (new != V4L2_MPEG_VIDEO_ASPECT_16x9)
471 new = V4L2_MPEG_VIDEO_ASPECT_4x3;
472 params->vi_aspect = new;
473 break;
474 case V4L2_CID_MPEG_VIDEO_BITRATE:
475 old = params->vi_bitrate * 1000;
476 new = 1000 * (new / 1000);
477 if (set && new > MPEG_VIDEO_TARGET_BITRATE_MAX * 1000)
478 return -ERANGE;
479 if (new > MPEG_VIDEO_TARGET_BITRATE_MAX * 1000)
480 new = MPEG_VIDEO_TARGET_BITRATE_MAX * 1000;
481 params->vi_bitrate = new / 1000;
482 break;
483 case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
484 old = params->vi_bitrate_peak * 1000;
485 new = 1000 * (new / 1000);
486 if (set && new > MPEG_VIDEO_TARGET_BITRATE_MAX * 1000)
487 return -ERANGE;
488 if (new > MPEG_VIDEO_TARGET_BITRATE_MAX * 1000)
489 new = MPEG_VIDEO_TARGET_BITRATE_MAX * 1000;
490 params->vi_bitrate_peak = new / 1000;
491 break;
492 case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
493 old = params->vi_bitrate_mode;
494 params->vi_bitrate_mode = new;
495 break;
496 default:
497 return -EINVAL;
498 }
499 if (cmd == VIDIOC_G_EXT_CTRLS)
500 ctrl->value = old;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501 else
Hans Verkuil86b79d62006-06-18 16:40:10 -0300502 ctrl->value = new;
503 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504}
505
Hans Verkuile281db582008-08-08 12:43:59 -0300506static int saa6752hs_qctrl(struct saa6752hs_state *h,
Hans Verkuil8b53b392008-06-27 21:18:15 -0300507 struct v4l2_queryctrl *qctrl)
508{
Hans Verkuile281db582008-08-08 12:43:59 -0300509 struct saa6752hs_mpeg_params *params = &h->params;
Hans Verkuil8b53b392008-06-27 21:18:15 -0300510 int err;
511
512 switch (qctrl->id) {
513 case V4L2_CID_MPEG_AUDIO_ENCODING:
514 return v4l2_ctrl_query_fill(qctrl,
515 V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
Hans Verkuile281db582008-08-08 12:43:59 -0300516 h->has_ac3 ? V4L2_MPEG_AUDIO_ENCODING_AC3 :
517 V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
518 1, V4L2_MPEG_AUDIO_ENCODING_LAYER_2);
Hans Verkuil8b53b392008-06-27 21:18:15 -0300519
520 case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
521 return v4l2_ctrl_query_fill(qctrl,
522 V4L2_MPEG_AUDIO_L2_BITRATE_256K,
523 V4L2_MPEG_AUDIO_L2_BITRATE_384K, 1,
524 V4L2_MPEG_AUDIO_L2_BITRATE_256K);
525
Hans Verkuile281db582008-08-08 12:43:59 -0300526 case V4L2_CID_MPEG_AUDIO_AC3_BITRATE:
527 if (!h->has_ac3)
528 return -EINVAL;
529 return v4l2_ctrl_query_fill(qctrl,
530 V4L2_MPEG_AUDIO_AC3_BITRATE_256K,
531 V4L2_MPEG_AUDIO_AC3_BITRATE_384K, 1,
532 V4L2_MPEG_AUDIO_AC3_BITRATE_256K);
533
Hans Verkuil8b53b392008-06-27 21:18:15 -0300534 case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
535 return v4l2_ctrl_query_fill(qctrl,
536 V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000,
537 V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000, 1,
538 V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000);
539
540 case V4L2_CID_MPEG_VIDEO_ENCODING:
541 return v4l2_ctrl_query_fill(qctrl,
542 V4L2_MPEG_VIDEO_ENCODING_MPEG_2,
543 V4L2_MPEG_VIDEO_ENCODING_MPEG_2, 1,
544 V4L2_MPEG_VIDEO_ENCODING_MPEG_2);
545
546 case V4L2_CID_MPEG_VIDEO_ASPECT:
547 return v4l2_ctrl_query_fill(qctrl,
548 V4L2_MPEG_VIDEO_ASPECT_4x3,
549 V4L2_MPEG_VIDEO_ASPECT_16x9, 1,
550 V4L2_MPEG_VIDEO_ASPECT_4x3);
551
552 case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
553 err = v4l2_ctrl_query_fill_std(qctrl);
554 if (err == 0 &&
555 params->vi_bitrate_mode ==
556 V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)
557 qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
558 return err;
559
560 case V4L2_CID_MPEG_STREAM_TYPE:
561 return v4l2_ctrl_query_fill(qctrl,
562 V4L2_MPEG_STREAM_TYPE_MPEG2_TS,
563 V4L2_MPEG_STREAM_TYPE_MPEG2_TS, 1,
564 V4L2_MPEG_STREAM_TYPE_MPEG2_TS);
565
566 case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
567 case V4L2_CID_MPEG_VIDEO_BITRATE:
568 case V4L2_CID_MPEG_STREAM_PID_PMT:
569 case V4L2_CID_MPEG_STREAM_PID_AUDIO:
570 case V4L2_CID_MPEG_STREAM_PID_VIDEO:
571 case V4L2_CID_MPEG_STREAM_PID_PCR:
572 return v4l2_ctrl_query_fill_std(qctrl);
573
574 default:
575 break;
576 }
577 return -EINVAL;
578}
579
Hans Verkuile281db582008-08-08 12:43:59 -0300580static int saa6752hs_qmenu(struct saa6752hs_state *h,
Hans Verkuil8b53b392008-06-27 21:18:15 -0300581 struct v4l2_querymenu *qmenu)
582{
Hans Verkuile281db582008-08-08 12:43:59 -0300583 static const u32 mpeg_audio_encoding[] = {
584 V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
585 V4L2_CTRL_MENU_IDS_END
586 };
587 static const u32 mpeg_audio_ac3_encoding[] = {
588 V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
589 V4L2_MPEG_AUDIO_ENCODING_AC3,
590 V4L2_CTRL_MENU_IDS_END
591 };
592 static u32 mpeg_audio_l2_bitrate[] = {
593 V4L2_MPEG_AUDIO_L2_BITRATE_256K,
594 V4L2_MPEG_AUDIO_L2_BITRATE_384K,
595 V4L2_CTRL_MENU_IDS_END
596 };
597 static u32 mpeg_audio_ac3_bitrate[] = {
598 V4L2_MPEG_AUDIO_AC3_BITRATE_256K,
599 V4L2_MPEG_AUDIO_AC3_BITRATE_384K,
600 V4L2_CTRL_MENU_IDS_END
Hans Verkuil8b53b392008-06-27 21:18:15 -0300601 };
602 struct v4l2_queryctrl qctrl;
603 int err;
604
605 qctrl.id = qmenu->id;
Hans Verkuile281db582008-08-08 12:43:59 -0300606 err = saa6752hs_qctrl(h, &qctrl);
Hans Verkuil8b53b392008-06-27 21:18:15 -0300607 if (err)
608 return err;
Hans Verkuile281db582008-08-08 12:43:59 -0300609 switch (qmenu->id) {
610 case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
611 return v4l2_ctrl_query_menu_valid_items(qmenu,
Hans Verkuil8b53b392008-06-27 21:18:15 -0300612 mpeg_audio_l2_bitrate);
Hans Verkuile281db582008-08-08 12:43:59 -0300613 case V4L2_CID_MPEG_AUDIO_AC3_BITRATE:
614 if (!h->has_ac3)
615 return -EINVAL;
616 return v4l2_ctrl_query_menu_valid_items(qmenu,
617 mpeg_audio_ac3_bitrate);
618 case V4L2_CID_MPEG_AUDIO_ENCODING:
619 return v4l2_ctrl_query_menu_valid_items(qmenu,
620 h->has_ac3 ? mpeg_audio_ac3_encoding :
621 mpeg_audio_encoding);
622 }
623 return v4l2_ctrl_query_menu(qmenu, &qctrl, NULL);
Hans Verkuil8b53b392008-06-27 21:18:15 -0300624}
625
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626static int saa6752hs_init(struct i2c_client* client)
627{
628 unsigned char buf[9], buf2[4];
629 struct saa6752hs_state *h;
630 u32 crc;
631 unsigned char localPAT[256];
632 unsigned char localPMT[256];
633
634 h = i2c_get_clientdata(client);
635
Robert W. Boone9b715212005-11-08 21:36:45 -0800636 /* Set video format - must be done first as it resets other settings */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637 buf[0] = 0x41;
Frederic CAND0a4c9c92005-05-05 16:15:52 -0700638 buf[1] = h->video_format;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639 i2c_master_send(client, buf, 2);
640
Robert W. Boone9b715212005-11-08 21:36:45 -0800641 /* Set number of lines in input signal */
642 buf[0] = 0x40;
643 buf[1] = 0x00;
644 if (h->standard & V4L2_STD_525_60)
645 buf[1] = 0x01;
646 i2c_master_send(client, buf, 2);
647
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800648 /* set bitrate */
Hans Verkuile281db582008-08-08 12:43:59 -0300649 saa6752hs_set_bitrate(client, h);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650
Robert W. Boone9b715212005-11-08 21:36:45 -0800651 /* Set GOP structure {3, 13} */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652 buf[0] = 0x72;
653 buf[1] = 0x03;
654 buf[2] = 0x0D;
655 i2c_master_send(client,buf,3);
656
Trent Piepho657de3c2006-06-20 00:30:57 -0300657 /* Set minimum Q-scale {4} */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658 buf[0] = 0x82;
659 buf[1] = 0x04;
660 i2c_master_send(client,buf,2);
661
Trent Piepho657de3c2006-06-20 00:30:57 -0300662 /* Set maximum Q-scale {12} */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663 buf[0] = 0x83;
664 buf[1] = 0x0C;
665 i2c_master_send(client,buf,2);
666
Trent Piepho657de3c2006-06-20 00:30:57 -0300667 /* Set Output Protocol */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 buf[0] = 0xD0;
669 buf[1] = 0x81;
670 i2c_master_send(client,buf,2);
671
Trent Piepho657de3c2006-06-20 00:30:57 -0300672 /* Set video output stream format {TS} */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673 buf[0] = 0xB0;
674 buf[1] = 0x05;
675 i2c_master_send(client,buf,2);
676
677 /* compute PAT */
678 memcpy(localPAT, PAT, sizeof(PAT));
679 localPAT[17] = 0xe0 | ((h->params.ts_pid_pmt >> 8) & 0x0f);
680 localPAT[18] = h->params.ts_pid_pmt & 0xff;
681 crc = crc32_be(~0, &localPAT[7], sizeof(PAT) - 7 - 4);
682 localPAT[sizeof(PAT) - 4] = (crc >> 24) & 0xFF;
683 localPAT[sizeof(PAT) - 3] = (crc >> 16) & 0xFF;
684 localPAT[sizeof(PAT) - 2] = (crc >> 8) & 0xFF;
685 localPAT[sizeof(PAT) - 1] = crc & 0xFF;
686
687 /* compute PMT */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800688 memcpy(localPMT, PMT, sizeof(PMT));
689 localPMT[3] = 0x40 | ((h->params.ts_pid_pmt >> 8) & 0x0f);
690 localPMT[4] = h->params.ts_pid_pmt & 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691 localPMT[15] = 0xE0 | ((h->params.ts_pid_pcr >> 8) & 0x0F);
692 localPMT[16] = h->params.ts_pid_pcr & 0xFF;
693 localPMT[20] = 0xE0 | ((h->params.ts_pid_video >> 8) & 0x0F);
694 localPMT[21] = h->params.ts_pid_video & 0xFF;
695 localPMT[25] = 0xE0 | ((h->params.ts_pid_audio >> 8) & 0x0F);
696 localPMT[26] = h->params.ts_pid_audio & 0xFF;
697 crc = crc32_be(~0, &localPMT[7], sizeof(PMT) - 7 - 4);
698 localPMT[sizeof(PMT) - 4] = (crc >> 24) & 0xFF;
699 localPMT[sizeof(PMT) - 3] = (crc >> 16) & 0xFF;
700 localPMT[sizeof(PMT) - 2] = (crc >> 8) & 0xFF;
701 localPMT[sizeof(PMT) - 1] = crc & 0xFF;
702
Trent Piepho657de3c2006-06-20 00:30:57 -0300703 /* Set Audio PID */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704 buf[0] = 0xC1;
705 buf[1] = (h->params.ts_pid_audio >> 8) & 0xFF;
706 buf[2] = h->params.ts_pid_audio & 0xFF;
707 i2c_master_send(client,buf,3);
708
Robert W. Boone9b715212005-11-08 21:36:45 -0800709 /* Set Video PID */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710 buf[0] = 0xC0;
711 buf[1] = (h->params.ts_pid_video >> 8) & 0xFF;
712 buf[2] = h->params.ts_pid_video & 0xFF;
713 i2c_master_send(client,buf,3);
714
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800715 /* Set PCR PID */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 buf[0] = 0xC4;
717 buf[1] = (h->params.ts_pid_pcr >> 8) & 0xFF;
718 buf[2] = h->params.ts_pid_pcr & 0xFF;
719 i2c_master_send(client,buf,3);
720
Robert W. Boone9b715212005-11-08 21:36:45 -0800721 /* Send SI tables */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 i2c_master_send(client,localPAT,sizeof(PAT));
723 i2c_master_send(client,localPMT,sizeof(PMT));
724
Robert W. Boone9b715212005-11-08 21:36:45 -0800725 /* mute then unmute audio. This removes buzzing artefacts */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726 buf[0] = 0xa4;
727 buf[1] = 1;
728 i2c_master_send(client, buf, 2);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800729 buf[1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730 i2c_master_send(client, buf, 2);
731
Robert W. Boone9b715212005-11-08 21:36:45 -0800732 /* start it going */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 saa6752hs_chip_command(client, SAA6752HS_COMMAND_START);
734
Robert W. Boone9b715212005-11-08 21:36:45 -0800735 /* readout current state */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736 buf[0] = 0xE1;
737 buf[1] = 0xA7;
738 buf[2] = 0xFE;
739 buf[3] = 0x82;
740 buf[4] = 0xB0;
741 i2c_master_send(client, buf, 5);
742 i2c_master_recv(client, buf2, 4);
743
Robert W. Boone9b715212005-11-08 21:36:45 -0800744 /* change aspect ratio */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745 buf[0] = 0xE0;
746 buf[1] = 0xA7;
747 buf[2] = 0xFE;
748 buf[3] = 0x82;
749 buf[4] = 0xB0;
750 buf[5] = buf2[0];
Hans Verkuil86b79d62006-06-18 16:40:10 -0300751 switch(h->params.vi_aspect) {
752 case V4L2_MPEG_VIDEO_ASPECT_16x9:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753 buf[6] = buf2[1] | 0x40;
754 break;
Hans Verkuil86b79d62006-06-18 16:40:10 -0300755 case V4L2_MPEG_VIDEO_ASPECT_4x3:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756 default:
757 buf[6] = buf2[1] & 0xBF;
758 break;
759 break;
760 }
761 buf[7] = buf2[2];
762 buf[8] = buf2[3];
763 i2c_master_send(client, buf, 9);
764
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765 return 0;
766}
767
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768static int
769saa6752hs_command(struct i2c_client *client, unsigned int cmd, void *arg)
770{
771 struct saa6752hs_state *h = i2c_get_clientdata(client);
Hans Verkuil86b79d62006-06-18 16:40:10 -0300772 struct v4l2_ext_controls *ctrls = arg;
Hans Verkuil86b79d62006-06-18 16:40:10 -0300773 struct saa6752hs_mpeg_params params;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774 int err = 0;
Hans Verkuil86b79d62006-06-18 16:40:10 -0300775 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800777 switch (cmd) {
Hans Verkuil86b79d62006-06-18 16:40:10 -0300778 case VIDIOC_S_EXT_CTRLS:
779 if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG)
780 return -EINVAL;
781 if (ctrls->count == 0) {
782 /* apply settings and start encoder */
783 saa6752hs_init(client);
784 break;
785 }
786 /* fall through */
787 case VIDIOC_TRY_EXT_CTRLS:
788 case VIDIOC_G_EXT_CTRLS:
789 if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG)
790 return -EINVAL;
791 params = h->params;
792 for (i = 0; i < ctrls->count; i++) {
Hans Verkuile281db582008-08-08 12:43:59 -0300793 err = handle_ctrl(h->has_ac3, &params, ctrls->controls + i, cmd);
794 if (err) {
Hans Verkuil86b79d62006-06-18 16:40:10 -0300795 ctrls->error_idx = i;
796 return err;
797 }
798 }
799 h->params = params;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800 break;
Hans Verkuil8b53b392008-06-27 21:18:15 -0300801 case VIDIOC_QUERYCTRL:
Hans Verkuile281db582008-08-08 12:43:59 -0300802 return saa6752hs_qctrl(h, arg);
Hans Verkuil8b53b392008-06-27 21:18:15 -0300803 case VIDIOC_QUERYMENU:
Hans Verkuile281db582008-08-08 12:43:59 -0300804 return saa6752hs_qmenu(h, arg);
Frederic CAND0a4c9c92005-05-05 16:15:52 -0700805 case VIDIOC_G_FMT:
806 {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800807 struct v4l2_format *f = arg;
Frederic CAND0a4c9c92005-05-05 16:15:52 -0700808
809 if (h->video_format == SAA6752HS_VF_UNKNOWN)
810 h->video_format = SAA6752HS_VF_D1;
811 f->fmt.pix.width =
812 v4l2_format_table[h->video_format].fmt.pix.width;
813 f->fmt.pix.height =
814 v4l2_format_table[h->video_format].fmt.pix.height;
815 break ;
816 }
817 case VIDIOC_S_FMT:
818 {
819 struct v4l2_format *f = arg;
820
821 saa6752hs_set_subsampling(client, f);
822 break;
823 }
Robert W. Boone9b715212005-11-08 21:36:45 -0800824 case VIDIOC_S_STD:
825 h->standard = *((v4l2_std_id *) arg);
826 break;
Hans Verkuile281db582008-08-08 12:43:59 -0300827
828 case VIDIOC_G_CHIP_IDENT:
829 return v4l2_chip_ident_i2c_client(client,
830 arg, h->chip, h->revision);
831
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 default:
833 /* nothing */
834 break;
835 }
836
837 return err;
838}
839
Hans Verkuile281db582008-08-08 12:43:59 -0300840static int saa6752hs_probe(struct i2c_client *client,
841 const struct i2c_device_id *id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842{
Hans Verkuile281db582008-08-08 12:43:59 -0300843 struct saa6752hs_state *h = kzalloc(sizeof(*h), GFP_KERNEL);
844 u8 addr = 0x13;
845 u8 data[12];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846
Hans Verkuile281db582008-08-08 12:43:59 -0300847 v4l_info(client, "chip found @ 0x%x (%s)\n",
848 client->addr << 1, client->adapter->name);
849 if (h == NULL)
850 return -ENOMEM;
851
852 i2c_master_send(client, &addr, 1);
853 i2c_master_recv(client, data, sizeof(data));
854 h->chip = V4L2_IDENT_SAA6752HS;
855 h->revision = (data[8] << 8) | data[9];
856 h->has_ac3 = 0;
857 if (h->revision == 0x0206) {
858 h->chip = V4L2_IDENT_SAA6752HS_AC3;
859 h->has_ac3 = 1;
860 v4l_info(client, "support AC-3\n");
861 }
862 h->params = param_defaults;
863 h->standard = 0; /* Assume 625 input lines */
864
865 i2c_set_clientdata(client, h);
866 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867}
868
Hans Verkuile281db582008-08-08 12:43:59 -0300869static int saa6752hs_remove(struct i2c_client *client)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870{
Hans Verkuile281db582008-08-08 12:43:59 -0300871 kfree(i2c_get_clientdata(client));
872 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873}
874
Hans Verkuile281db582008-08-08 12:43:59 -0300875static const struct i2c_device_id saa6752hs_id[] = {
876 { "saa6752hs", 0 },
877 { }
878};
879MODULE_DEVICE_TABLE(i2c, saa6752hs_id);
880
881static struct v4l2_i2c_driver_data v4l2_i2c_data = {
882 .name = "saa6752hs",
883 .driverid = I2C_DRIVERID_SAA6752HS,
884 .command = saa6752hs_command,
885 .probe = saa6752hs_probe,
886 .remove = saa6752hs_remove,
887 .id_table = saa6752hs_id,
888};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889
890/*
891 * Overrides for Emacs so that we follow Linus's tabbing style.
892 * ---------------------------------------------------------------------------
893 * Local variables:
894 * c-basic-offset: 8
895 * End:
896 */