xref: /openbmc/linux/drivers/media/i2c/saa6752hs.c (revision 8774bed9ce832d8d9ccb79e92800b808aa2d2ad2)
16052ba35SHans Verkuil  /*
26052ba35SHans Verkuil     saa6752hs - i2c-driver for the saa6752hs by Philips
36052ba35SHans Verkuil 
46052ba35SHans Verkuil     Copyright (C) 2004 Andrew de Quincey
56052ba35SHans Verkuil 
66052ba35SHans Verkuil     AC-3 support:
76052ba35SHans Verkuil 
86052ba35SHans Verkuil     Copyright (C) 2008 Hans Verkuil <hverkuil@xs4all.nl>
96052ba35SHans Verkuil 
106052ba35SHans Verkuil     This program is free software; you can redistribute it and/or modify
116052ba35SHans Verkuil     it under the terms of the GNU General Public License vs published by
126052ba35SHans Verkuil     the Free Software Foundation; either version 2 of the License, or
136052ba35SHans Verkuil     (at your option) any later version.
146052ba35SHans Verkuil 
156052ba35SHans Verkuil     This program is distributed in the hope that it will be useful,
166052ba35SHans Verkuil     but WITHOUT ANY WARRANTY; without even the implied warranty of
176052ba35SHans Verkuil     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
186052ba35SHans Verkuil     GNU General Public License for more details.
196052ba35SHans Verkuil 
206052ba35SHans Verkuil     You should have received a copy of the GNU General Public License
216052ba35SHans Verkuil     along with this program; if not, write to the Free Software
226052ba35SHans Verkuil     Foundation, Inc., 675 Mvss Ave, Cambridge, MA 02139, USA.
236052ba35SHans Verkuil   */
246052ba35SHans Verkuil 
256052ba35SHans Verkuil #include <linux/module.h>
266052ba35SHans Verkuil #include <linux/kernel.h>
276052ba35SHans Verkuil #include <linux/string.h>
286052ba35SHans Verkuil #include <linux/timer.h>
296052ba35SHans Verkuil #include <linux/delay.h>
306052ba35SHans Verkuil #include <linux/errno.h>
316052ba35SHans Verkuil #include <linux/slab.h>
326052ba35SHans Verkuil #include <linux/poll.h>
336052ba35SHans Verkuil #include <linux/i2c.h>
346052ba35SHans Verkuil #include <linux/types.h>
356052ba35SHans Verkuil #include <linux/videodev2.h>
366052ba35SHans Verkuil #include <linux/init.h>
376052ba35SHans Verkuil #include <linux/crc32.h>
386052ba35SHans Verkuil #include <media/v4l2-device.h>
396052ba35SHans Verkuil #include <media/v4l2-ctrls.h>
406052ba35SHans Verkuil #include <media/v4l2-common.h>
416052ba35SHans Verkuil 
426052ba35SHans Verkuil #define MPEG_VIDEO_TARGET_BITRATE_MAX  27000
436052ba35SHans Verkuil #define MPEG_VIDEO_MAX_BITRATE_MAX     27000
446052ba35SHans Verkuil #define MPEG_TOTAL_TARGET_BITRATE_MAX  27000
456052ba35SHans Verkuil #define MPEG_PID_MAX ((1 << 14) - 1)
466052ba35SHans Verkuil 
476052ba35SHans Verkuil 
486052ba35SHans Verkuil MODULE_DESCRIPTION("device driver for saa6752hs MPEG2 encoder");
496052ba35SHans Verkuil MODULE_AUTHOR("Andrew de Quincey");
506052ba35SHans Verkuil MODULE_LICENSE("GPL");
516052ba35SHans Verkuil 
526052ba35SHans Verkuil enum saa6752hs_videoformat {
536052ba35SHans Verkuil 	SAA6752HS_VF_D1 = 0,    /* standard D1 video format: 720x576 */
546052ba35SHans Verkuil 	SAA6752HS_VF_2_3_D1 = 1,/* 2/3D1 video format: 480x576 */
556052ba35SHans Verkuil 	SAA6752HS_VF_1_2_D1 = 2,/* 1/2D1 video format: 352x576 */
566052ba35SHans Verkuil 	SAA6752HS_VF_SIF = 3,   /* SIF video format: 352x288 */
576052ba35SHans Verkuil 	SAA6752HS_VF_UNKNOWN,
586052ba35SHans Verkuil };
596052ba35SHans Verkuil 
606052ba35SHans Verkuil struct saa6752hs_mpeg_params {
616052ba35SHans Verkuil 	/* transport streams */
626052ba35SHans Verkuil 	__u16				ts_pid_pmt;
636052ba35SHans Verkuil 	__u16				ts_pid_audio;
646052ba35SHans Verkuil 	__u16				ts_pid_video;
656052ba35SHans Verkuil 	__u16				ts_pid_pcr;
666052ba35SHans Verkuil 
676052ba35SHans Verkuil 	/* audio */
686052ba35SHans Verkuil 	enum v4l2_mpeg_audio_encoding    au_encoding;
696052ba35SHans Verkuil 	enum v4l2_mpeg_audio_l2_bitrate  au_l2_bitrate;
706052ba35SHans Verkuil 	enum v4l2_mpeg_audio_ac3_bitrate au_ac3_bitrate;
716052ba35SHans Verkuil 
726052ba35SHans Verkuil 	/* video */
736052ba35SHans Verkuil 	enum v4l2_mpeg_video_aspect	vi_aspect;
746052ba35SHans Verkuil 	enum v4l2_mpeg_video_bitrate_mode vi_bitrate_mode;
756052ba35SHans Verkuil 	__u32 				vi_bitrate;
766052ba35SHans Verkuil 	__u32 				vi_bitrate_peak;
776052ba35SHans Verkuil };
786052ba35SHans Verkuil 
796052ba35SHans Verkuil static const struct v4l2_format v4l2_format_table[] =
806052ba35SHans Verkuil {
816052ba35SHans Verkuil 	[SAA6752HS_VF_D1] =
826052ba35SHans Verkuil 		{ .fmt = { .pix = { .width = 720, .height = 576 }}},
836052ba35SHans Verkuil 	[SAA6752HS_VF_2_3_D1] =
846052ba35SHans Verkuil 		{ .fmt = { .pix = { .width = 480, .height = 576 }}},
856052ba35SHans Verkuil 	[SAA6752HS_VF_1_2_D1] =
866052ba35SHans Verkuil 		{ .fmt = { .pix = { .width = 352, .height = 576 }}},
876052ba35SHans Verkuil 	[SAA6752HS_VF_SIF] =
886052ba35SHans Verkuil 		{ .fmt = { .pix = { .width = 352, .height = 288 }}},
896052ba35SHans Verkuil 	[SAA6752HS_VF_UNKNOWN] =
906052ba35SHans Verkuil 		{ .fmt = { .pix = { .width = 0, .height = 0}}},
916052ba35SHans Verkuil };
926052ba35SHans Verkuil 
936052ba35SHans Verkuil struct saa6752hs_state {
946052ba35SHans Verkuil 	struct v4l2_subdev            sd;
956052ba35SHans Verkuil 	struct v4l2_ctrl_handler      hdl;
966052ba35SHans Verkuil 	struct { /* video bitrate mode control cluster */
976052ba35SHans Verkuil 		struct v4l2_ctrl *video_bitrate_mode;
986052ba35SHans Verkuil 		struct v4l2_ctrl *video_bitrate;
996052ba35SHans Verkuil 		struct v4l2_ctrl *video_bitrate_peak;
1006052ba35SHans Verkuil 	};
1016052ba35SHans Verkuil 	u32 			      revision;
1026052ba35SHans Verkuil 	int 			      has_ac3;
1036052ba35SHans Verkuil 	struct saa6752hs_mpeg_params  params;
1046052ba35SHans Verkuil 	enum saa6752hs_videoformat    video_format;
1056052ba35SHans Verkuil 	v4l2_std_id                   standard;
1066052ba35SHans Verkuil };
1076052ba35SHans Verkuil 
1086052ba35SHans Verkuil enum saa6752hs_command {
1096052ba35SHans Verkuil 	SAA6752HS_COMMAND_RESET = 0,
1106052ba35SHans Verkuil 	SAA6752HS_COMMAND_STOP = 1,
1116052ba35SHans Verkuil 	SAA6752HS_COMMAND_START = 2,
1126052ba35SHans Verkuil 	SAA6752HS_COMMAND_PAUSE = 3,
1136052ba35SHans Verkuil 	SAA6752HS_COMMAND_RECONFIGURE = 4,
1146052ba35SHans Verkuil 	SAA6752HS_COMMAND_SLEEP = 5,
1156052ba35SHans Verkuil 	SAA6752HS_COMMAND_RECONFIGURE_FORCE = 6,
1166052ba35SHans Verkuil 
1176052ba35SHans Verkuil 	SAA6752HS_COMMAND_MAX
1186052ba35SHans Verkuil };
1196052ba35SHans Verkuil 
1206052ba35SHans Verkuil static inline struct saa6752hs_state *to_state(struct v4l2_subdev *sd)
1216052ba35SHans Verkuil {
1226052ba35SHans Verkuil 	return container_of(sd, struct saa6752hs_state, sd);
1236052ba35SHans Verkuil }
1246052ba35SHans Verkuil 
1256052ba35SHans Verkuil /* ---------------------------------------------------------------------- */
1266052ba35SHans Verkuil 
1276052ba35SHans Verkuil static const u8 PAT[] = {
1286052ba35SHans Verkuil 	0xc2, /* i2c register */
1296052ba35SHans Verkuil 	0x00, /* table number for encoder */
1306052ba35SHans Verkuil 
1316052ba35SHans Verkuil 	0x47, /* sync */
1326052ba35SHans Verkuil 	0x40, 0x00, /* transport_error_indicator(0), payload_unit_start(1), transport_priority(0), pid(0) */
1336052ba35SHans Verkuil 	0x10, /* transport_scrambling_control(00), adaptation_field_control(01), continuity_counter(0) */
1346052ba35SHans Verkuil 
1356052ba35SHans Verkuil 	0x00, /* PSI pointer to start of table */
1366052ba35SHans Verkuil 
1376052ba35SHans Verkuil 	0x00, /* tid(0) */
1386052ba35SHans Verkuil 	0xb0, 0x0d, /* section_syntax_indicator(1), section_length(13) */
1396052ba35SHans Verkuil 
1406052ba35SHans Verkuil 	0x00, 0x01, /* transport_stream_id(1) */
1416052ba35SHans Verkuil 
1426052ba35SHans Verkuil 	0xc1, /* version_number(0), current_next_indicator(1) */
1436052ba35SHans Verkuil 
1446052ba35SHans Verkuil 	0x00, 0x00, /* section_number(0), last_section_number(0) */
1456052ba35SHans Verkuil 
1466052ba35SHans Verkuil 	0x00, 0x01, /* program_number(1) */
1476052ba35SHans Verkuil 
1486052ba35SHans Verkuil 	0xe0, 0x00, /* PMT PID */
1496052ba35SHans Verkuil 
1506052ba35SHans Verkuil 	0x00, 0x00, 0x00, 0x00 /* CRC32 */
1516052ba35SHans Verkuil };
1526052ba35SHans Verkuil 
1536052ba35SHans Verkuil static const u8 PMT[] = {
1546052ba35SHans Verkuil 	0xc2, /* i2c register */
1556052ba35SHans Verkuil 	0x01, /* table number for encoder */
1566052ba35SHans Verkuil 
1576052ba35SHans Verkuil 	0x47, /* sync */
1586052ba35SHans Verkuil 	0x40, 0x00, /* transport_error_indicator(0), payload_unit_start(1), transport_priority(0), pid */
1596052ba35SHans Verkuil 	0x10, /* transport_scrambling_control(00), adaptation_field_control(01), continuity_counter(0) */
1606052ba35SHans Verkuil 
1616052ba35SHans Verkuil 	0x00, /* PSI pointer to start of table */
1626052ba35SHans Verkuil 
1636052ba35SHans Verkuil 	0x02, /* tid(2) */
1646052ba35SHans Verkuil 	0xb0, 0x17, /* section_syntax_indicator(1), section_length(23) */
1656052ba35SHans Verkuil 
1666052ba35SHans Verkuil 	0x00, 0x01, /* program_number(1) */
1676052ba35SHans Verkuil 
1686052ba35SHans Verkuil 	0xc1, /* version_number(0), current_next_indicator(1) */
1696052ba35SHans Verkuil 
1706052ba35SHans Verkuil 	0x00, 0x00, /* section_number(0), last_section_number(0) */
1716052ba35SHans Verkuil 
1726052ba35SHans Verkuil 	0xe0, 0x00, /* PCR_PID */
1736052ba35SHans Verkuil 
1746052ba35SHans Verkuil 	0xf0, 0x00, /* program_info_length(0) */
1756052ba35SHans Verkuil 
1766052ba35SHans Verkuil 	0x02, 0xe0, 0x00, 0xf0, 0x00, /* video stream type(2), pid */
1776052ba35SHans Verkuil 	0x04, 0xe0, 0x00, 0xf0, 0x00, /* audio stream type(4), pid */
1786052ba35SHans Verkuil 
1796052ba35SHans Verkuil 	0x00, 0x00, 0x00, 0x00 /* CRC32 */
1806052ba35SHans Verkuil };
1816052ba35SHans Verkuil 
1826052ba35SHans Verkuil static const u8 PMT_AC3[] = {
1836052ba35SHans Verkuil 	0xc2, /* i2c register */
1846052ba35SHans Verkuil 	0x01, /* table number for encoder(1) */
1856052ba35SHans Verkuil 	0x47, /* sync */
1866052ba35SHans Verkuil 
1876052ba35SHans Verkuil 	0x40, /* transport_error_indicator(0), payload_unit_start(1), transport_priority(0) */
1886052ba35SHans Verkuil 	0x10, /* PMT PID (0x0010) */
1896052ba35SHans Verkuil 	0x10, /* transport_scrambling_control(00), adaptation_field_control(01), continuity_counter(0) */
1906052ba35SHans Verkuil 
1916052ba35SHans Verkuil 	0x00, /* PSI pointer to start of table */
1926052ba35SHans Verkuil 
1936052ba35SHans Verkuil 	0x02, /* TID (2) */
1946052ba35SHans Verkuil 	0xb0, 0x1a, /* section_syntax_indicator(1), section_length(26) */
1956052ba35SHans Verkuil 
1966052ba35SHans Verkuil 	0x00, 0x01, /* program_number(1) */
1976052ba35SHans Verkuil 
1986052ba35SHans Verkuil 	0xc1, /* version_number(0), current_next_indicator(1) */
1996052ba35SHans Verkuil 
2006052ba35SHans Verkuil 	0x00, 0x00, /* section_number(0), last_section_number(0) */
2016052ba35SHans Verkuil 
2026052ba35SHans Verkuil 	0xe1, 0x04, /* PCR_PID (0x0104) */
2036052ba35SHans Verkuil 
2046052ba35SHans Verkuil 	0xf0, 0x00, /* program_info_length(0) */
2056052ba35SHans Verkuil 
2066052ba35SHans Verkuil 	0x02, 0xe1, 0x00, 0xf0, 0x00, /* video stream type(2), pid */
2076052ba35SHans Verkuil 	0x06, 0xe1, 0x03, 0xf0, 0x03, /* audio stream type(6), pid */
2086052ba35SHans Verkuil 	0x6a, /* AC3 */
2096052ba35SHans Verkuil 	0x01, /* Descriptor_length(1) */
2106052ba35SHans Verkuil 	0x00, /* component_type_flag(0), bsid_flag(0), mainid_flag(0), asvc_flag(0), reserved flags(0) */
2116052ba35SHans Verkuil 
2126052ba35SHans Verkuil 	0xED, 0xDE, 0x2D, 0xF3 /* CRC32 BE */
2136052ba35SHans Verkuil };
2146052ba35SHans Verkuil 
2156052ba35SHans Verkuil static const struct saa6752hs_mpeg_params param_defaults =
2166052ba35SHans Verkuil {
2176052ba35SHans Verkuil 	.ts_pid_pmt      = 16,
2186052ba35SHans Verkuil 	.ts_pid_video    = 260,
2196052ba35SHans Verkuil 	.ts_pid_audio    = 256,
2206052ba35SHans Verkuil 	.ts_pid_pcr      = 259,
2216052ba35SHans Verkuil 
2226052ba35SHans Verkuil 	.vi_aspect       = V4L2_MPEG_VIDEO_ASPECT_4x3,
2236052ba35SHans Verkuil 	.vi_bitrate      = 4000,
2246052ba35SHans Verkuil 	.vi_bitrate_peak = 6000,
2256052ba35SHans Verkuil 	.vi_bitrate_mode = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
2266052ba35SHans Verkuil 
2276052ba35SHans Verkuil 	.au_encoding     = V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
2286052ba35SHans Verkuil 	.au_l2_bitrate   = V4L2_MPEG_AUDIO_L2_BITRATE_256K,
2296052ba35SHans Verkuil 	.au_ac3_bitrate  = V4L2_MPEG_AUDIO_AC3_BITRATE_256K,
2306052ba35SHans Verkuil };
2316052ba35SHans Verkuil 
2326052ba35SHans Verkuil /* ---------------------------------------------------------------------- */
2336052ba35SHans Verkuil 
2346052ba35SHans Verkuil static int saa6752hs_chip_command(struct i2c_client *client,
2356052ba35SHans Verkuil 				  enum saa6752hs_command command)
2366052ba35SHans Verkuil {
2376052ba35SHans Verkuil 	unsigned char buf[3];
2386052ba35SHans Verkuil 	unsigned long timeout;
2396052ba35SHans Verkuil 	int status = 0;
2406052ba35SHans Verkuil 
2416052ba35SHans Verkuil 	/* execute the command */
2426052ba35SHans Verkuil 	switch(command) {
2436052ba35SHans Verkuil 	case SAA6752HS_COMMAND_RESET:
2446052ba35SHans Verkuil 		buf[0] = 0x00;
2456052ba35SHans Verkuil 		break;
2466052ba35SHans Verkuil 
2476052ba35SHans Verkuil 	case SAA6752HS_COMMAND_STOP:
2486052ba35SHans Verkuil 		buf[0] = 0x03;
2496052ba35SHans Verkuil 		break;
2506052ba35SHans Verkuil 
2516052ba35SHans Verkuil 	case SAA6752HS_COMMAND_START:
2526052ba35SHans Verkuil 		buf[0] = 0x02;
2536052ba35SHans Verkuil 		break;
2546052ba35SHans Verkuil 
2556052ba35SHans Verkuil 	case SAA6752HS_COMMAND_PAUSE:
2566052ba35SHans Verkuil 		buf[0] = 0x04;
2576052ba35SHans Verkuil 		break;
2586052ba35SHans Verkuil 
2596052ba35SHans Verkuil 	case SAA6752HS_COMMAND_RECONFIGURE:
2606052ba35SHans Verkuil 		buf[0] = 0x05;
2616052ba35SHans Verkuil 		break;
2626052ba35SHans Verkuil 
2636052ba35SHans Verkuil 	case SAA6752HS_COMMAND_SLEEP:
2646052ba35SHans Verkuil 		buf[0] = 0x06;
2656052ba35SHans Verkuil 		break;
2666052ba35SHans Verkuil 
2676052ba35SHans Verkuil 	case SAA6752HS_COMMAND_RECONFIGURE_FORCE:
2686052ba35SHans Verkuil 		buf[0] = 0x07;
2696052ba35SHans Verkuil 		break;
2706052ba35SHans Verkuil 
2716052ba35SHans Verkuil 	default:
2726052ba35SHans Verkuil 		return -EINVAL;
2736052ba35SHans Verkuil 	}
2746052ba35SHans Verkuil 
2756052ba35SHans Verkuil 	/* set it and wait for it to be so */
2766052ba35SHans Verkuil 	i2c_master_send(client, buf, 1);
2776052ba35SHans Verkuil 	timeout = jiffies + HZ * 3;
2786052ba35SHans Verkuil 	for (;;) {
2796052ba35SHans Verkuil 		/* get the current status */
2806052ba35SHans Verkuil 		buf[0] = 0x10;
2816052ba35SHans Verkuil 		i2c_master_send(client, buf, 1);
2826052ba35SHans Verkuil 		i2c_master_recv(client, buf, 1);
2836052ba35SHans Verkuil 
2846052ba35SHans Verkuil 		if (!(buf[0] & 0x20))
2856052ba35SHans Verkuil 			break;
2866052ba35SHans Verkuil 		if (time_after(jiffies,timeout)) {
2876052ba35SHans Verkuil 			status = -ETIMEDOUT;
2886052ba35SHans Verkuil 			break;
2896052ba35SHans Verkuil 		}
2906052ba35SHans Verkuil 
2916052ba35SHans Verkuil 		msleep(10);
2926052ba35SHans Verkuil 	}
2936052ba35SHans Verkuil 
2946052ba35SHans Verkuil 	/* delay a bit to let encoder settle */
2956052ba35SHans Verkuil 	msleep(50);
2966052ba35SHans Verkuil 
2976052ba35SHans Verkuil 	return status;
2986052ba35SHans Verkuil }
2996052ba35SHans Verkuil 
3006052ba35SHans Verkuil 
3016052ba35SHans Verkuil static inline void set_reg8(struct i2c_client *client, uint8_t reg, uint8_t val)
3026052ba35SHans Verkuil {
3036052ba35SHans Verkuil 	u8 buf[2];
3046052ba35SHans Verkuil 
3056052ba35SHans Verkuil 	buf[0] = reg;
3066052ba35SHans Verkuil 	buf[1] = val;
3076052ba35SHans Verkuil 	i2c_master_send(client, buf, 2);
3086052ba35SHans Verkuil }
3096052ba35SHans Verkuil 
3106052ba35SHans Verkuil static inline void set_reg16(struct i2c_client *client, uint8_t reg, uint16_t val)
3116052ba35SHans Verkuil {
3126052ba35SHans Verkuil 	u8 buf[3];
3136052ba35SHans Verkuil 
3146052ba35SHans Verkuil 	buf[0] = reg;
3156052ba35SHans Verkuil 	buf[1] = val >> 8;
3166052ba35SHans Verkuil 	buf[2] = val & 0xff;
3176052ba35SHans Verkuil 	i2c_master_send(client, buf, 3);
3186052ba35SHans Verkuil }
3196052ba35SHans Verkuil 
3206052ba35SHans Verkuil static int saa6752hs_set_bitrate(struct i2c_client *client,
3216052ba35SHans Verkuil 				 struct saa6752hs_state *h)
3226052ba35SHans Verkuil {
3236052ba35SHans Verkuil 	struct saa6752hs_mpeg_params *params = &h->params;
3246052ba35SHans Verkuil 	int tot_bitrate;
3256052ba35SHans Verkuil 	int is_384k;
3266052ba35SHans Verkuil 
3276052ba35SHans Verkuil 	/* set the bitrate mode */
3286052ba35SHans Verkuil 	set_reg8(client, 0x71,
3296052ba35SHans Verkuil 		params->vi_bitrate_mode != V4L2_MPEG_VIDEO_BITRATE_MODE_VBR);
3306052ba35SHans Verkuil 
3316052ba35SHans Verkuil 	/* set the video bitrate */
3326052ba35SHans Verkuil 	if (params->vi_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) {
3336052ba35SHans Verkuil 		/* set the target bitrate */
3346052ba35SHans Verkuil 		set_reg16(client, 0x80, params->vi_bitrate);
3356052ba35SHans Verkuil 
3366052ba35SHans Verkuil 		/* set the max bitrate */
3376052ba35SHans Verkuil 		set_reg16(client, 0x81, params->vi_bitrate_peak);
3386052ba35SHans Verkuil 		tot_bitrate = params->vi_bitrate_peak;
3396052ba35SHans Verkuil 	} else {
3406052ba35SHans Verkuil 		/* set the target bitrate (no max bitrate for CBR) */
3416052ba35SHans Verkuil 		set_reg16(client, 0x81, params->vi_bitrate);
3426052ba35SHans Verkuil 		tot_bitrate = params->vi_bitrate;
3436052ba35SHans Verkuil 	}
3446052ba35SHans Verkuil 
3456052ba35SHans Verkuil 	/* set the audio encoding */
3466052ba35SHans Verkuil 	set_reg8(client, 0x93,
3476052ba35SHans Verkuil 			params->au_encoding == V4L2_MPEG_AUDIO_ENCODING_AC3);
3486052ba35SHans Verkuil 
3496052ba35SHans Verkuil 	/* set the audio bitrate */
3506052ba35SHans Verkuil 	if (params->au_encoding == V4L2_MPEG_AUDIO_ENCODING_AC3)
3516052ba35SHans Verkuil 		is_384k = V4L2_MPEG_AUDIO_AC3_BITRATE_384K == params->au_ac3_bitrate;
3526052ba35SHans Verkuil 	else
3536052ba35SHans Verkuil 		is_384k = V4L2_MPEG_AUDIO_L2_BITRATE_384K == params->au_l2_bitrate;
3546052ba35SHans Verkuil 	set_reg8(client, 0x94, is_384k);
3556052ba35SHans Verkuil 	tot_bitrate += is_384k ? 384 : 256;
3566052ba35SHans Verkuil 
3576052ba35SHans Verkuil 	/* Note: the total max bitrate is determined by adding the video and audio
3586052ba35SHans Verkuil 	   bitrates together and also adding an extra 768kbit/s to stay on the
3596052ba35SHans Verkuil 	   safe side. If more control should be required, then an extra MPEG control
3606052ba35SHans Verkuil 	   should be added. */
3616052ba35SHans Verkuil 	tot_bitrate += 768;
3626052ba35SHans Verkuil 	if (tot_bitrate > MPEG_TOTAL_TARGET_BITRATE_MAX)
3636052ba35SHans Verkuil 		tot_bitrate = MPEG_TOTAL_TARGET_BITRATE_MAX;
3646052ba35SHans Verkuil 
3656052ba35SHans Verkuil 	/* set the total bitrate */
3666052ba35SHans Verkuil 	set_reg16(client, 0xb1, tot_bitrate);
3676052ba35SHans Verkuil 	return 0;
3686052ba35SHans Verkuil }
3696052ba35SHans Verkuil 
3706052ba35SHans Verkuil static int saa6752hs_try_ctrl(struct v4l2_ctrl *ctrl)
3716052ba35SHans Verkuil {
3726052ba35SHans Verkuil 	struct saa6752hs_state *h =
3736052ba35SHans Verkuil 		container_of(ctrl->handler, struct saa6752hs_state, hdl);
3746052ba35SHans Verkuil 
3756052ba35SHans Verkuil 	switch (ctrl->id) {
3766052ba35SHans Verkuil 	case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
3776052ba35SHans Verkuil 		/* peak bitrate shall be >= normal bitrate */
3786052ba35SHans Verkuil 		if (ctrl->val == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR &&
3796052ba35SHans Verkuil 		    h->video_bitrate_peak->val < h->video_bitrate->val)
3806052ba35SHans Verkuil 			h->video_bitrate_peak->val = h->video_bitrate->val;
3816052ba35SHans Verkuil 		break;
3826052ba35SHans Verkuil 	}
3836052ba35SHans Verkuil 	return 0;
3846052ba35SHans Verkuil }
3856052ba35SHans Verkuil 
3866052ba35SHans Verkuil static int saa6752hs_s_ctrl(struct v4l2_ctrl *ctrl)
3876052ba35SHans Verkuil {
3886052ba35SHans Verkuil 	struct saa6752hs_state *h =
3896052ba35SHans Verkuil 		container_of(ctrl->handler, struct saa6752hs_state, hdl);
3906052ba35SHans Verkuil 	struct saa6752hs_mpeg_params *params = &h->params;
3916052ba35SHans Verkuil 
3926052ba35SHans Verkuil 	switch (ctrl->id) {
3936052ba35SHans Verkuil 	case V4L2_CID_MPEG_STREAM_TYPE:
3946052ba35SHans Verkuil 		break;
3956052ba35SHans Verkuil 	case V4L2_CID_MPEG_STREAM_PID_PMT:
3966052ba35SHans Verkuil 		params->ts_pid_pmt = ctrl->val;
3976052ba35SHans Verkuil 		break;
3986052ba35SHans Verkuil 	case V4L2_CID_MPEG_STREAM_PID_AUDIO:
3996052ba35SHans Verkuil 		params->ts_pid_audio = ctrl->val;
4006052ba35SHans Verkuil 		break;
4016052ba35SHans Verkuil 	case V4L2_CID_MPEG_STREAM_PID_VIDEO:
4026052ba35SHans Verkuil 		params->ts_pid_video = ctrl->val;
4036052ba35SHans Verkuil 		break;
4046052ba35SHans Verkuil 	case V4L2_CID_MPEG_STREAM_PID_PCR:
4056052ba35SHans Verkuil 		params->ts_pid_pcr = ctrl->val;
4066052ba35SHans Verkuil 		break;
4076052ba35SHans Verkuil 	case V4L2_CID_MPEG_AUDIO_ENCODING:
4086052ba35SHans Verkuil 		params->au_encoding = ctrl->val;
4096052ba35SHans Verkuil 		break;
4106052ba35SHans Verkuil 	case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
4116052ba35SHans Verkuil 		params->au_l2_bitrate = ctrl->val;
4126052ba35SHans Verkuil 		break;
4136052ba35SHans Verkuil 	case V4L2_CID_MPEG_AUDIO_AC3_BITRATE:
4146052ba35SHans Verkuil 		params->au_ac3_bitrate = ctrl->val;
4156052ba35SHans Verkuil 		break;
4166052ba35SHans Verkuil 	case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
4176052ba35SHans Verkuil 		break;
4186052ba35SHans Verkuil 	case V4L2_CID_MPEG_VIDEO_ENCODING:
4196052ba35SHans Verkuil 		break;
4206052ba35SHans Verkuil 	case V4L2_CID_MPEG_VIDEO_ASPECT:
4216052ba35SHans Verkuil 		params->vi_aspect = ctrl->val;
4226052ba35SHans Verkuil 		break;
4236052ba35SHans Verkuil 	case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
4246052ba35SHans Verkuil 		params->vi_bitrate_mode = ctrl->val;
4256052ba35SHans Verkuil 		params->vi_bitrate = h->video_bitrate->val / 1000;
4266052ba35SHans Verkuil 		params->vi_bitrate_peak = h->video_bitrate_peak->val / 1000;
4276052ba35SHans Verkuil 		v4l2_ctrl_activate(h->video_bitrate_peak,
4286052ba35SHans Verkuil 				ctrl->val == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR);
4296052ba35SHans Verkuil 		break;
4306052ba35SHans Verkuil 	default:
4316052ba35SHans Verkuil 		return -EINVAL;
4326052ba35SHans Verkuil 	}
4336052ba35SHans Verkuil 	return 0;
4346052ba35SHans Verkuil }
4356052ba35SHans Verkuil 
4366052ba35SHans Verkuil static int saa6752hs_init(struct v4l2_subdev *sd, u32 leading_null_bytes)
4376052ba35SHans Verkuil {
4386052ba35SHans Verkuil 	unsigned char buf[9], buf2[4];
4396052ba35SHans Verkuil 	struct saa6752hs_state *h = to_state(sd);
4406052ba35SHans Verkuil 	struct i2c_client *client = v4l2_get_subdevdata(sd);
4416052ba35SHans Verkuil 	unsigned size;
4426052ba35SHans Verkuil 	u32 crc;
4436052ba35SHans Verkuil 	unsigned char localPAT[256];
4446052ba35SHans Verkuil 	unsigned char localPMT[256];
4456052ba35SHans Verkuil 
4466052ba35SHans Verkuil 	/* Set video format - must be done first as it resets other settings */
4476052ba35SHans Verkuil 	set_reg8(client, 0x41, h->video_format);
4486052ba35SHans Verkuil 
4496052ba35SHans Verkuil 	/* Set number of lines in input signal */
4506052ba35SHans Verkuil 	set_reg8(client, 0x40, (h->standard & V4L2_STD_525_60) ? 1 : 0);
4516052ba35SHans Verkuil 
4526052ba35SHans Verkuil 	/* set bitrate */
4536052ba35SHans Verkuil 	saa6752hs_set_bitrate(client, h);
4546052ba35SHans Verkuil 
4556052ba35SHans Verkuil 	/* Set GOP structure {3, 13} */
4566052ba35SHans Verkuil 	set_reg16(client, 0x72, 0x030d);
4576052ba35SHans Verkuil 
4586052ba35SHans Verkuil 	/* Set minimum Q-scale {4} */
4596052ba35SHans Verkuil 	set_reg8(client, 0x82, 0x04);
4606052ba35SHans Verkuil 
4616052ba35SHans Verkuil 	/* Set maximum Q-scale {12} */
4626052ba35SHans Verkuil 	set_reg8(client, 0x83, 0x0c);
4636052ba35SHans Verkuil 
4646052ba35SHans Verkuil 	/* Set Output Protocol */
4656052ba35SHans Verkuil 	set_reg8(client, 0xd0, 0x81);
4666052ba35SHans Verkuil 
4676052ba35SHans Verkuil 	/* Set video output stream format {TS} */
4686052ba35SHans Verkuil 	set_reg8(client, 0xb0, 0x05);
4696052ba35SHans Verkuil 
4706052ba35SHans Verkuil 	/* Set leading null byte for TS */
4716052ba35SHans Verkuil 	set_reg16(client, 0xf6, leading_null_bytes);
4726052ba35SHans Verkuil 
4736052ba35SHans Verkuil 	/* compute PAT */
4746052ba35SHans Verkuil 	memcpy(localPAT, PAT, sizeof(PAT));
4756052ba35SHans Verkuil 	localPAT[17] = 0xe0 | ((h->params.ts_pid_pmt >> 8) & 0x0f);
4766052ba35SHans Verkuil 	localPAT[18] = h->params.ts_pid_pmt & 0xff;
4776052ba35SHans Verkuil 	crc = crc32_be(~0, &localPAT[7], sizeof(PAT) - 7 - 4);
4786052ba35SHans Verkuil 	localPAT[sizeof(PAT) - 4] = (crc >> 24) & 0xFF;
4796052ba35SHans Verkuil 	localPAT[sizeof(PAT) - 3] = (crc >> 16) & 0xFF;
4806052ba35SHans Verkuil 	localPAT[sizeof(PAT) - 2] = (crc >> 8) & 0xFF;
4816052ba35SHans Verkuil 	localPAT[sizeof(PAT) - 1] = crc & 0xFF;
4826052ba35SHans Verkuil 
4836052ba35SHans Verkuil 	/* compute PMT */
4846052ba35SHans Verkuil 	if (h->params.au_encoding == V4L2_MPEG_AUDIO_ENCODING_AC3) {
4856052ba35SHans Verkuil 		size = sizeof(PMT_AC3);
4866052ba35SHans Verkuil 		memcpy(localPMT, PMT_AC3, size);
4876052ba35SHans Verkuil 	} else {
4886052ba35SHans Verkuil 		size = sizeof(PMT);
4896052ba35SHans Verkuil 		memcpy(localPMT, PMT, size);
4906052ba35SHans Verkuil 	}
4916052ba35SHans Verkuil 	localPMT[3] = 0x40 | ((h->params.ts_pid_pmt >> 8) & 0x0f);
4926052ba35SHans Verkuil 	localPMT[4] = h->params.ts_pid_pmt & 0xff;
4936052ba35SHans Verkuil 	localPMT[15] = 0xE0 | ((h->params.ts_pid_pcr >> 8) & 0x0F);
4946052ba35SHans Verkuil 	localPMT[16] = h->params.ts_pid_pcr & 0xFF;
4956052ba35SHans Verkuil 	localPMT[20] = 0xE0 | ((h->params.ts_pid_video >> 8) & 0x0F);
4966052ba35SHans Verkuil 	localPMT[21] = h->params.ts_pid_video & 0xFF;
4976052ba35SHans Verkuil 	localPMT[25] = 0xE0 | ((h->params.ts_pid_audio >> 8) & 0x0F);
4986052ba35SHans Verkuil 	localPMT[26] = h->params.ts_pid_audio & 0xFF;
4996052ba35SHans Verkuil 	crc = crc32_be(~0, &localPMT[7], size - 7 - 4);
5006052ba35SHans Verkuil 	localPMT[size - 4] = (crc >> 24) & 0xFF;
5016052ba35SHans Verkuil 	localPMT[size - 3] = (crc >> 16) & 0xFF;
5026052ba35SHans Verkuil 	localPMT[size - 2] = (crc >> 8) & 0xFF;
5036052ba35SHans Verkuil 	localPMT[size - 1] = crc & 0xFF;
5046052ba35SHans Verkuil 
5056052ba35SHans Verkuil 	/* Set Audio PID */
5066052ba35SHans Verkuil 	set_reg16(client, 0xc1, h->params.ts_pid_audio);
5076052ba35SHans Verkuil 
5086052ba35SHans Verkuil 	/* Set Video PID */
5096052ba35SHans Verkuil 	set_reg16(client, 0xc0, h->params.ts_pid_video);
5106052ba35SHans Verkuil 
5116052ba35SHans Verkuil 	/* Set PCR PID */
5126052ba35SHans Verkuil 	set_reg16(client, 0xc4, h->params.ts_pid_pcr);
5136052ba35SHans Verkuil 
5146052ba35SHans Verkuil 	/* Send SI tables */
5156052ba35SHans Verkuil 	i2c_master_send(client, localPAT, sizeof(PAT));
5166052ba35SHans Verkuil 	i2c_master_send(client, localPMT, size);
5176052ba35SHans Verkuil 
5186052ba35SHans Verkuil 	/* mute then unmute audio. This removes buzzing artefacts */
5196052ba35SHans Verkuil 	set_reg8(client, 0xa4, 1);
5206052ba35SHans Verkuil 	set_reg8(client, 0xa4, 0);
5216052ba35SHans Verkuil 
5226052ba35SHans Verkuil 	/* start it going */
5236052ba35SHans Verkuil 	saa6752hs_chip_command(client, SAA6752HS_COMMAND_START);
5246052ba35SHans Verkuil 
5256052ba35SHans Verkuil 	/* readout current state */
5266052ba35SHans Verkuil 	buf[0] = 0xE1;
5276052ba35SHans Verkuil 	buf[1] = 0xA7;
5286052ba35SHans Verkuil 	buf[2] = 0xFE;
5296052ba35SHans Verkuil 	buf[3] = 0x82;
5306052ba35SHans Verkuil 	buf[4] = 0xB0;
5316052ba35SHans Verkuil 	i2c_master_send(client, buf, 5);
5326052ba35SHans Verkuil 	i2c_master_recv(client, buf2, 4);
5336052ba35SHans Verkuil 
5346052ba35SHans Verkuil 	/* change aspect ratio */
5356052ba35SHans Verkuil 	buf[0] = 0xE0;
5366052ba35SHans Verkuil 	buf[1] = 0xA7;
5376052ba35SHans Verkuil 	buf[2] = 0xFE;
5386052ba35SHans Verkuil 	buf[3] = 0x82;
5396052ba35SHans Verkuil 	buf[4] = 0xB0;
5406052ba35SHans Verkuil 	buf[5] = buf2[0];
5416052ba35SHans Verkuil 	switch (h->params.vi_aspect) {
5426052ba35SHans Verkuil 	case V4L2_MPEG_VIDEO_ASPECT_16x9:
5436052ba35SHans Verkuil 		buf[6] = buf2[1] | 0x40;
5446052ba35SHans Verkuil 		break;
5456052ba35SHans Verkuil 	case V4L2_MPEG_VIDEO_ASPECT_4x3:
5466052ba35SHans Verkuil 	default:
5476052ba35SHans Verkuil 		buf[6] = buf2[1] & 0xBF;
5486052ba35SHans Verkuil 		break;
5496052ba35SHans Verkuil 	}
5506052ba35SHans Verkuil 	buf[7] = buf2[2];
5516052ba35SHans Verkuil 	buf[8] = buf2[3];
5526052ba35SHans Verkuil 	i2c_master_send(client, buf, 9);
5536052ba35SHans Verkuil 
5546052ba35SHans Verkuil 	return 0;
5556052ba35SHans Verkuil }
5566052ba35SHans Verkuil 
5576052ba35SHans Verkuil static int saa6752hs_g_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *f)
5586052ba35SHans Verkuil {
5596052ba35SHans Verkuil 	struct saa6752hs_state *h = to_state(sd);
5606052ba35SHans Verkuil 
5616052ba35SHans Verkuil 	if (h->video_format == SAA6752HS_VF_UNKNOWN)
5626052ba35SHans Verkuil 		h->video_format = SAA6752HS_VF_D1;
5636052ba35SHans Verkuil 	f->width = v4l2_format_table[h->video_format].fmt.pix.width;
5646052ba35SHans Verkuil 	f->height = v4l2_format_table[h->video_format].fmt.pix.height;
5656052ba35SHans Verkuil 	f->code = V4L2_MBUS_FMT_FIXED;
5666052ba35SHans Verkuil 	f->field = V4L2_FIELD_INTERLACED;
5676052ba35SHans Verkuil 	f->colorspace = V4L2_COLORSPACE_SMPTE170M;
5686052ba35SHans Verkuil 	return 0;
5696052ba35SHans Verkuil }
5706052ba35SHans Verkuil 
5716052ba35SHans Verkuil static int saa6752hs_try_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *f)
5726052ba35SHans Verkuil {
5736052ba35SHans Verkuil 	int dist_352, dist_480, dist_720;
5746052ba35SHans Verkuil 
5756052ba35SHans Verkuil 	f->code = V4L2_MBUS_FMT_FIXED;
5766052ba35SHans Verkuil 
5776052ba35SHans Verkuil 	dist_352 = abs(f->width - 352);
5786052ba35SHans Verkuil 	dist_480 = abs(f->width - 480);
5796052ba35SHans Verkuil 	dist_720 = abs(f->width - 720);
5806052ba35SHans Verkuil 	if (dist_720 < dist_480) {
5816052ba35SHans Verkuil 		f->width = 720;
5826052ba35SHans Verkuil 		f->height = 576;
5836052ba35SHans Verkuil 	} else if (dist_480 < dist_352) {
5846052ba35SHans Verkuil 		f->width = 480;
5856052ba35SHans Verkuil 		f->height = 576;
5866052ba35SHans Verkuil 	} else {
5876052ba35SHans Verkuil 		f->width = 352;
5886052ba35SHans Verkuil 		if (abs(f->height - 576) < abs(f->height - 288))
5896052ba35SHans Verkuil 			f->height = 576;
5906052ba35SHans Verkuil 		else
5916052ba35SHans Verkuil 			f->height = 288;
5926052ba35SHans Verkuil 	}
5936052ba35SHans Verkuil 	f->field = V4L2_FIELD_INTERLACED;
5946052ba35SHans Verkuil 	f->colorspace = V4L2_COLORSPACE_SMPTE170M;
5956052ba35SHans Verkuil 	return 0;
5966052ba35SHans Verkuil }
5976052ba35SHans Verkuil 
5986052ba35SHans Verkuil static int saa6752hs_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *f)
5996052ba35SHans Verkuil {
6006052ba35SHans Verkuil 	struct saa6752hs_state *h = to_state(sd);
6016052ba35SHans Verkuil 
6026052ba35SHans Verkuil 	if (f->code != V4L2_MBUS_FMT_FIXED)
6036052ba35SHans Verkuil 		return -EINVAL;
6046052ba35SHans Verkuil 
6056052ba35SHans Verkuil 	/*
6066052ba35SHans Verkuil 	  FIXME: translate and round width/height into EMPRESS
6076052ba35SHans Verkuil 	  subsample type:
6086052ba35SHans Verkuil 
6096052ba35SHans Verkuil 	  type   |   PAL   |  NTSC
6106052ba35SHans Verkuil 	  ---------------------------
6116052ba35SHans Verkuil 	  SIF    | 352x288 | 352x240
6126052ba35SHans Verkuil 	  1/2 D1 | 352x576 | 352x480
6136052ba35SHans Verkuil 	  2/3 D1 | 480x576 | 480x480
6146052ba35SHans Verkuil 	  D1     | 720x576 | 720x480
6156052ba35SHans Verkuil 	*/
6166052ba35SHans Verkuil 
6176052ba35SHans Verkuil 	saa6752hs_try_mbus_fmt(sd, f);
6186052ba35SHans Verkuil 	if (f->width == 720)
6196052ba35SHans Verkuil 		h->video_format = SAA6752HS_VF_D1;
6206052ba35SHans Verkuil 	else if (f->width == 480)
6216052ba35SHans Verkuil 		h->video_format = SAA6752HS_VF_2_3_D1;
6226052ba35SHans Verkuil 	else if (f->height == 576)
6236052ba35SHans Verkuil 		h->video_format = SAA6752HS_VF_1_2_D1;
6246052ba35SHans Verkuil 	else
6256052ba35SHans Verkuil 		h->video_format = SAA6752HS_VF_SIF;
6266052ba35SHans Verkuil 	return 0;
6276052ba35SHans Verkuil }
6286052ba35SHans Verkuil 
6296052ba35SHans Verkuil static int saa6752hs_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
6306052ba35SHans Verkuil {
6316052ba35SHans Verkuil 	struct saa6752hs_state *h = to_state(sd);
6326052ba35SHans Verkuil 
6336052ba35SHans Verkuil 	h->standard = std;
6346052ba35SHans Verkuil 	return 0;
6356052ba35SHans Verkuil }
6366052ba35SHans Verkuil 
6376052ba35SHans Verkuil /* ----------------------------------------------------------------------- */
6386052ba35SHans Verkuil 
6396052ba35SHans Verkuil static const struct v4l2_ctrl_ops saa6752hs_ctrl_ops = {
6406052ba35SHans Verkuil 	.try_ctrl = saa6752hs_try_ctrl,
6416052ba35SHans Verkuil 	.s_ctrl = saa6752hs_s_ctrl,
6426052ba35SHans Verkuil };
6436052ba35SHans Verkuil 
6446052ba35SHans Verkuil static const struct v4l2_subdev_core_ops saa6752hs_core_ops = {
6456052ba35SHans Verkuil 	.init = saa6752hs_init,
6466052ba35SHans Verkuil };
6476052ba35SHans Verkuil 
6486052ba35SHans Verkuil static const struct v4l2_subdev_video_ops saa6752hs_video_ops = {
649*8774bed9SLaurent Pinchart 	.s_std = saa6752hs_s_std,
6506052ba35SHans Verkuil 	.s_mbus_fmt = saa6752hs_s_mbus_fmt,
6516052ba35SHans Verkuil 	.try_mbus_fmt = saa6752hs_try_mbus_fmt,
6526052ba35SHans Verkuil 	.g_mbus_fmt = saa6752hs_g_mbus_fmt,
6536052ba35SHans Verkuil };
6546052ba35SHans Verkuil 
6556052ba35SHans Verkuil static const struct v4l2_subdev_ops saa6752hs_ops = {
6566052ba35SHans Verkuil 	.core = &saa6752hs_core_ops,
6576052ba35SHans Verkuil 	.video = &saa6752hs_video_ops,
6586052ba35SHans Verkuil };
6596052ba35SHans Verkuil 
6606052ba35SHans Verkuil static int saa6752hs_probe(struct i2c_client *client,
6616052ba35SHans Verkuil 		const struct i2c_device_id *id)
6626052ba35SHans Verkuil {
6636052ba35SHans Verkuil 	struct saa6752hs_state *h = kzalloc(sizeof(*h), GFP_KERNEL);
6646052ba35SHans Verkuil 	struct v4l2_subdev *sd;
6656052ba35SHans Verkuil 	struct v4l2_ctrl_handler *hdl;
6666052ba35SHans Verkuil 	u8 addr = 0x13;
6676052ba35SHans Verkuil 	u8 data[12];
6686052ba35SHans Verkuil 
6696052ba35SHans Verkuil 	v4l_info(client, "chip found @ 0x%x (%s)\n",
6706052ba35SHans Verkuil 			client->addr << 1, client->adapter->name);
6716052ba35SHans Verkuil 	if (h == NULL)
6726052ba35SHans Verkuil 		return -ENOMEM;
6736052ba35SHans Verkuil 	sd = &h->sd;
6746052ba35SHans Verkuil 	v4l2_i2c_subdev_init(sd, client, &saa6752hs_ops);
6756052ba35SHans Verkuil 
6766052ba35SHans Verkuil 	i2c_master_send(client, &addr, 1);
6776052ba35SHans Verkuil 	i2c_master_recv(client, data, sizeof(data));
6786052ba35SHans Verkuil 	h->revision = (data[8] << 8) | data[9];
6796052ba35SHans Verkuil 	h->has_ac3 = 0;
6806052ba35SHans Verkuil 	if (h->revision == 0x0206) {
6816052ba35SHans Verkuil 		h->has_ac3 = 1;
6826052ba35SHans Verkuil 		v4l_info(client, "supports AC-3\n");
6836052ba35SHans Verkuil 	}
6846052ba35SHans Verkuil 	h->params = param_defaults;
6856052ba35SHans Verkuil 
6866052ba35SHans Verkuil 	hdl = &h->hdl;
6876052ba35SHans Verkuil 	v4l2_ctrl_handler_init(hdl, 14);
6886052ba35SHans Verkuil 	v4l2_ctrl_new_std_menu(hdl, &saa6752hs_ctrl_ops,
6896052ba35SHans Verkuil 		V4L2_CID_MPEG_AUDIO_ENCODING,
6906052ba35SHans Verkuil 		h->has_ac3 ? V4L2_MPEG_AUDIO_ENCODING_AC3 :
6916052ba35SHans Verkuil 			V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
6926052ba35SHans Verkuil 		0x0d, V4L2_MPEG_AUDIO_ENCODING_LAYER_2);
6936052ba35SHans Verkuil 
6946052ba35SHans Verkuil 	v4l2_ctrl_new_std_menu(hdl, &saa6752hs_ctrl_ops,
6956052ba35SHans Verkuil 		V4L2_CID_MPEG_AUDIO_L2_BITRATE,
6966052ba35SHans Verkuil 		V4L2_MPEG_AUDIO_L2_BITRATE_384K,
6976052ba35SHans Verkuil 		~((1 << V4L2_MPEG_AUDIO_L2_BITRATE_256K) |
6986052ba35SHans Verkuil 		  (1 << V4L2_MPEG_AUDIO_L2_BITRATE_384K)),
6996052ba35SHans Verkuil 		V4L2_MPEG_AUDIO_L2_BITRATE_256K);
7006052ba35SHans Verkuil 
7016052ba35SHans Verkuil 	if (h->has_ac3)
7026052ba35SHans Verkuil 		v4l2_ctrl_new_std_menu(hdl, &saa6752hs_ctrl_ops,
7036052ba35SHans Verkuil 			V4L2_CID_MPEG_AUDIO_AC3_BITRATE,
7046052ba35SHans Verkuil 			V4L2_MPEG_AUDIO_AC3_BITRATE_384K,
7056052ba35SHans Verkuil 			~((1 << V4L2_MPEG_AUDIO_AC3_BITRATE_256K) |
7066052ba35SHans Verkuil 			  (1 << V4L2_MPEG_AUDIO_AC3_BITRATE_384K)),
7076052ba35SHans Verkuil 			V4L2_MPEG_AUDIO_AC3_BITRATE_256K);
7086052ba35SHans Verkuil 
7096052ba35SHans Verkuil 	v4l2_ctrl_new_std_menu(hdl, &saa6752hs_ctrl_ops,
7106052ba35SHans Verkuil 		V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ,
7116052ba35SHans Verkuil 		V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000,
7126052ba35SHans Verkuil 		~(1 << V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000),
7136052ba35SHans Verkuil 		V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000);
7146052ba35SHans Verkuil 
7156052ba35SHans Verkuil 	v4l2_ctrl_new_std_menu(hdl, &saa6752hs_ctrl_ops,
7166052ba35SHans Verkuil 		V4L2_CID_MPEG_VIDEO_ENCODING,
7176052ba35SHans Verkuil 		V4L2_MPEG_VIDEO_ENCODING_MPEG_2,
7186052ba35SHans Verkuil 		~(1 << V4L2_MPEG_VIDEO_ENCODING_MPEG_2),
7196052ba35SHans Verkuil 		V4L2_MPEG_VIDEO_ENCODING_MPEG_2);
7206052ba35SHans Verkuil 
7216052ba35SHans Verkuil 	v4l2_ctrl_new_std_menu(hdl, &saa6752hs_ctrl_ops,
7226052ba35SHans Verkuil 		V4L2_CID_MPEG_VIDEO_ASPECT,
7236052ba35SHans Verkuil 		V4L2_MPEG_VIDEO_ASPECT_16x9, 0x01,
7246052ba35SHans Verkuil 		V4L2_MPEG_VIDEO_ASPECT_4x3);
7256052ba35SHans Verkuil 
7266052ba35SHans Verkuil 	h->video_bitrate_peak = v4l2_ctrl_new_std(hdl, &saa6752hs_ctrl_ops,
7276052ba35SHans Verkuil 		V4L2_CID_MPEG_VIDEO_BITRATE_PEAK,
7286052ba35SHans Verkuil 		1000000, 27000000, 1000, 8000000);
7296052ba35SHans Verkuil 
7306052ba35SHans Verkuil 	v4l2_ctrl_new_std_menu(hdl, &saa6752hs_ctrl_ops,
7316052ba35SHans Verkuil 		V4L2_CID_MPEG_STREAM_TYPE,
7326052ba35SHans Verkuil 		V4L2_MPEG_STREAM_TYPE_MPEG2_TS,
7336052ba35SHans Verkuil 		~(1 << V4L2_MPEG_STREAM_TYPE_MPEG2_TS),
7346052ba35SHans Verkuil 		V4L2_MPEG_STREAM_TYPE_MPEG2_TS);
7356052ba35SHans Verkuil 
7366052ba35SHans Verkuil 	h->video_bitrate_mode = v4l2_ctrl_new_std_menu(hdl, &saa6752hs_ctrl_ops,
7376052ba35SHans Verkuil 		V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
7386052ba35SHans Verkuil 		V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, 0,
7396052ba35SHans Verkuil 		V4L2_MPEG_VIDEO_BITRATE_MODE_VBR);
7406052ba35SHans Verkuil 	h->video_bitrate = v4l2_ctrl_new_std(hdl, &saa6752hs_ctrl_ops,
7416052ba35SHans Verkuil 		V4L2_CID_MPEG_VIDEO_BITRATE, 1000000, 27000000, 1000, 6000000);
7426052ba35SHans Verkuil 	v4l2_ctrl_new_std(hdl, &saa6752hs_ctrl_ops,
7436052ba35SHans Verkuil 		V4L2_CID_MPEG_STREAM_PID_PMT, 0, (1 << 14) - 1, 1, 16);
7446052ba35SHans Verkuil 	v4l2_ctrl_new_std(hdl, &saa6752hs_ctrl_ops,
7456052ba35SHans Verkuil 		V4L2_CID_MPEG_STREAM_PID_AUDIO, 0, (1 << 14) - 1, 1, 260);
7466052ba35SHans Verkuil 	v4l2_ctrl_new_std(hdl, &saa6752hs_ctrl_ops,
7476052ba35SHans Verkuil 		V4L2_CID_MPEG_STREAM_PID_VIDEO, 0, (1 << 14) - 1, 1, 256);
7486052ba35SHans Verkuil 	v4l2_ctrl_new_std(hdl, &saa6752hs_ctrl_ops,
7496052ba35SHans Verkuil 		V4L2_CID_MPEG_STREAM_PID_PCR, 0, (1 << 14) - 1, 1, 259);
7506052ba35SHans Verkuil 	sd->ctrl_handler = hdl;
7516052ba35SHans Verkuil 	if (hdl->error) {
7526052ba35SHans Verkuil 		int err = hdl->error;
7536052ba35SHans Verkuil 
7546052ba35SHans Verkuil 		v4l2_ctrl_handler_free(hdl);
7556052ba35SHans Verkuil 		kfree(h);
7566052ba35SHans Verkuil 		return err;
7576052ba35SHans Verkuil 	}
7586052ba35SHans Verkuil 	v4l2_ctrl_cluster(3, &h->video_bitrate_mode);
7596052ba35SHans Verkuil 	v4l2_ctrl_handler_setup(hdl);
7606052ba35SHans Verkuil 	h->standard = 0; /* Assume 625 input lines */
7616052ba35SHans Verkuil 	return 0;
7626052ba35SHans Verkuil }
7636052ba35SHans Verkuil 
7646052ba35SHans Verkuil static int saa6752hs_remove(struct i2c_client *client)
7656052ba35SHans Verkuil {
7666052ba35SHans Verkuil 	struct v4l2_subdev *sd = i2c_get_clientdata(client);
7676052ba35SHans Verkuil 
7686052ba35SHans Verkuil 	v4l2_device_unregister_subdev(sd);
7696052ba35SHans Verkuil 	v4l2_ctrl_handler_free(&to_state(sd)->hdl);
7706052ba35SHans Verkuil 	kfree(to_state(sd));
7716052ba35SHans Verkuil 	return 0;
7726052ba35SHans Verkuil }
7736052ba35SHans Verkuil 
7746052ba35SHans Verkuil static const struct i2c_device_id saa6752hs_id[] = {
7756052ba35SHans Verkuil 	{ "saa6752hs", 0 },
7766052ba35SHans Verkuil 	{ }
7776052ba35SHans Verkuil };
7786052ba35SHans Verkuil MODULE_DEVICE_TABLE(i2c, saa6752hs_id);
7796052ba35SHans Verkuil 
7806052ba35SHans Verkuil static struct i2c_driver saa6752hs_driver = {
7816052ba35SHans Verkuil 	.driver = {
7826052ba35SHans Verkuil 		.owner	= THIS_MODULE,
7836052ba35SHans Verkuil 		.name	= "saa6752hs",
7846052ba35SHans Verkuil 	},
7856052ba35SHans Verkuil 	.probe		= saa6752hs_probe,
7866052ba35SHans Verkuil 	.remove		= saa6752hs_remove,
7876052ba35SHans Verkuil 	.id_table	= saa6752hs_id,
7886052ba35SHans Verkuil };
7896052ba35SHans Verkuil 
7906052ba35SHans Verkuil module_i2c_driver(saa6752hs_driver);
791