1 #include <linux/module.h>
2 #include <linux/kernel.h>
3 #include <linux/sched.h>
4 #include <linux/string.h>
5 #include <linux/timer.h>
6 #include <linux/delay.h>
7 #include <linux/errno.h>
8 #include <linux/slab.h>
9 #include <linux/poll.h>
10 #include <linux/i2c.h>
11 #include <linux/types.h>
12 #include <linux/videodev.h>
13 #include <linux/init.h>
16 #include <media/saa6752hs.h>
18 /* Addresses to scan */
19 static unsigned short normal_i2c[] = {0x20, I2C_CLIENT_END};
20 static unsigned short normal_i2c_range[] = {I2C_CLIENT_END};
23 MODULE_DESCRIPTION("device driver for saa6752hs MPEG2 encoder");
24 MODULE_AUTHOR("Andrew de Quincey");
25 MODULE_LICENSE("GPL");
27 static struct i2c_driver driver;
28 static struct i2c_client client_template;
31 enum saa6752hs_command {
32 SAA6752HS_COMMAND_RESET = 0,
33 SAA6752HS_COMMAND_STOP = 1,
34 SAA6752HS_COMMAND_START = 2,
35 SAA6752HS_COMMAND_PAUSE = 3,
36 SAA6752HS_COMMAND_RECONFIGURE = 4,
37 SAA6752HS_COMMAND_SLEEP = 5,
38 SAA6752HS_COMMAND_RECONFIGURE_FORCE = 6,
44 /* ---------------------------------------------------------------------- */
48 0x00, // table number for encoder
51 0x40, 0x00, // transport_error_indicator(0), payload_unit_start(1), transport_priority(0), pid(0)
52 0x10, // transport_scrambling_control(00), adaptation_field_control(01), continuity_counter(0)
54 0x00, // PSI pointer to start of table
57 0xb0, 0x0d, // section_syntax_indicator(1), section_length(13)
59 0x00, 0x01, // transport_stream_id(1)
61 0xc1, // version_number(0), current_next_indicator(1)
63 0x00, 0x00, // section_number(0), last_section_number(0)
65 0x00, 0x01, // program_number(1)
67 0xe0, 0x10, // PMT PID(0x10)
69 0x76, 0xf1, 0x44, 0xd1 // CRC32
74 0x01, // table number for encoder
77 0x40, 0x10, // transport_error_indicator(0), payload_unit_start(1), transport_priority(0), pid(0x10)
78 0x10, // transport_scrambling_control(00), adaptation_field_control(01), continuity_counter(0)
80 0x00, // PSI pointer to start of table
83 0xb0, 0x17, // section_syntax_indicator(1), section_length(23)
85 0x00, 0x01, // program_number(1)
87 0xc1, // version_number(0), current_next_indicator(1)
89 0x00, 0x00, // section_number(0), last_section_number(0)
91 0xe1, 0x04, // PCR_PID (0x104)
93 0xf0, 0x00, // program_info_length(0)
95 0x02, 0xe1, 0x00, 0xf0, 0x00, // video stream type(2), pid(0x100)
96 0x04, 0xe1, 0x03, 0xf0, 0x00, // audio stream type(4), pid(0x103)
98 0xa1, 0xca, 0x0f, 0x82 // CRC32
101 static struct mpeg_params mpeg_params_template =
103 .bitrate_mode = MPEG_BITRATE_MODE_CBR,
104 .video_target_bitrate = 5000,
105 .audio_bitrate = MPEG_AUDIO_BITRATE_256,
106 .total_bitrate = 6000,
110 /* ---------------------------------------------------------------------- */
113 static int saa6752hs_chip_command(struct i2c_client* client,
114 enum saa6752hs_command command)
116 unsigned char buf[3];
117 unsigned long timeout;
120 // execute the command
122 case SAA6752HS_COMMAND_RESET:
126 case SAA6752HS_COMMAND_STOP:
130 case SAA6752HS_COMMAND_START:
134 case SAA6752HS_COMMAND_PAUSE:
138 case SAA6752HS_COMMAND_RECONFIGURE:
142 case SAA6752HS_COMMAND_SLEEP:
146 case SAA6752HS_COMMAND_RECONFIGURE_FORCE:
154 // set it and wait for it to be so
155 i2c_master_send(client, buf, 1);
156 timeout = jiffies + HZ * 3;
158 // get the current status
160 i2c_master_send(client, buf, 1);
161 i2c_master_recv(client, buf, 1);
163 if (!(buf[0] & 0x20))
165 if (time_after(jiffies,timeout)) {
171 set_current_state(TASK_INTERRUPTIBLE);
172 schedule_timeout(HZ/100);
175 // delay a bit to let encoder settle
176 set_current_state(TASK_INTERRUPTIBLE);
177 schedule_timeout(HZ/20);
184 static int saa6752hs_set_bitrate(struct i2c_client* client,
185 struct mpeg_params* params)
189 // set the bitrate mode
191 buf[1] = params->bitrate_mode;
192 i2c_master_send(client, buf, 2);
194 // set the video bitrate
195 if (params->bitrate_mode == MPEG_BITRATE_MODE_VBR) {
196 // set the target bitrate
198 buf[1] = params->video_target_bitrate >> 8;
199 buf[2] = params->video_target_bitrate & 0xff;
200 i2c_master_send(client, buf, 3);
202 // set the max bitrate
204 buf[1] = params->video_max_bitrate >> 8;
205 buf[2] = params->video_max_bitrate & 0xff;
206 i2c_master_send(client, buf, 3);
208 // set the target bitrate (no max bitrate for CBR)
210 buf[1] = params->video_target_bitrate >> 8;
211 buf[2] = params->video_target_bitrate & 0xff;
212 i2c_master_send(client, buf, 3);
215 // set the audio bitrate
217 buf[1] = params->audio_bitrate;
218 i2c_master_send(client, buf, 2);
220 // set the total bitrate
222 buf[1] = params->total_bitrate >> 8;
223 buf[2] = params->total_bitrate & 0xff;
224 i2c_master_send(client, buf, 3);
230 static int saa6752hs_init(struct i2c_client* client, struct mpeg_params* params)
232 unsigned char buf[3];
235 // check the bitrate parameters first
236 if (params != NULL) {
237 if (params->bitrate_mode >= MPEG_BITRATE_MODE_MAX)
239 if (params->video_target_bitrate >= MPEG_VIDEO_TARGET_BITRATE_MAX)
241 if (params->video_max_bitrate >= MPEG_VIDEO_MAX_BITRATE_MAX)
243 if (params->audio_bitrate >= MPEG_AUDIO_BITRATE_MAX)
245 if (params->total_bitrate >= MPEG_TOTAL_BITRATE_MAX)
247 if (params->bitrate_mode == MPEG_BITRATE_MODE_MAX &&
248 params->video_target_bitrate <= params->video_max_bitrate)
252 // Set GOP structure {3, 13}
256 i2c_master_send(client,buf,3);
258 // Set minimum Q-scale {4}
261 i2c_master_send(client,buf,2);
263 // Set maximum Q-scale {12}
266 i2c_master_send(client,buf,2);
268 // Set Output Protocol
271 i2c_master_send(client,buf,2);
273 // Set video output stream format {TS}
276 i2c_master_send(client,buf,2);
278 // Set Audio PID {0x103}
282 i2c_master_send(client,buf,3);
284 // setup bitrate settings
285 data = i2c_get_clientdata(client);
287 saa6752hs_set_bitrate(client, params);
288 memcpy(data, params, sizeof(struct mpeg_params));
290 // parameters were not supplied. use the previous set
291 saa6752hs_set_bitrate(client, (struct mpeg_params*) data);
295 i2c_master_send(client,PAT,sizeof(PAT));
296 i2c_master_send(client,PMT,sizeof(PMT));
298 // mute then unmute audio. This removes buzzing artefacts
301 i2c_master_send(client, buf, 2);
303 i2c_master_send(client, buf, 2);
306 saa6752hs_chip_command(client, SAA6752HS_COMMAND_START);
311 static int saa6752hs_attach(struct i2c_adapter *adap, int addr, int kind)
313 struct i2c_client *client;
314 struct mpeg_params* params;
316 client_template.adapter = adap;
317 client_template.addr = addr;
319 printk("saa6752hs: chip found @ 0x%x\n", addr<<1);
321 if (NULL == (client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL)))
323 memcpy(client,&client_template,sizeof(struct i2c_client));
324 strlcpy(client->name, "saa6752hs", sizeof(client->name));
326 if (NULL == (params = kmalloc(sizeof(struct mpeg_params), GFP_KERNEL)))
328 memcpy(params,&mpeg_params_template,sizeof(struct mpeg_params));
329 i2c_set_clientdata(client, params);
331 i2c_attach_client(client);
336 static int saa6752hs_probe(struct i2c_adapter *adap)
338 if (adap->class & I2C_CLASS_TV_ANALOG)
339 return i2c_probe(adap, &addr_data, saa6752hs_attach);
344 static int saa6752hs_detach(struct i2c_client *client)
348 data = i2c_get_clientdata(client);
349 i2c_detach_client(client);
356 saa6752hs_command(struct i2c_client *client, unsigned int cmd, void *arg)
358 struct mpeg_params* init_arg = arg;
362 return saa6752hs_init(client, init_arg);
372 /* ----------------------------------------------------------------------- */
374 static struct i2c_driver driver = {
375 .owner = THIS_MODULE,
376 .name = "i2c saa6752hs MPEG encoder",
377 .id = I2C_DRIVERID_SAA6752HS,
378 .flags = I2C_DF_NOTIFY,
379 .attach_adapter = saa6752hs_probe,
380 .detach_client = saa6752hs_detach,
381 .command = saa6752hs_command,
384 static struct i2c_client client_template =
386 I2C_DEVNAME("(saa6752hs unset)"),
387 .flags = I2C_CLIENT_ALLOW_USE,
391 static int saa6752hs_init_module(void)
393 i2c_add_driver(&driver);
397 static void saa6752hs_cleanup_module(void)
399 i2c_del_driver(&driver);
402 module_init(saa6752hs_init_module);
403 module_exit(saa6752hs_cleanup_module);
406 * Overrides for Emacs so that we follow Linus's tabbing style.
407 * ---------------------------------------------------------------------------