diff options
Diffstat (limited to 'drivers/media/video/saa7127.c')
-rw-r--r-- | drivers/media/video/saa7127.c | 421 |
1 files changed, 232 insertions, 189 deletions
diff --git a/drivers/media/video/saa7127.c b/drivers/media/video/saa7127.c index cc02fb18efa7..bfc85654795e 100644 --- a/drivers/media/video/saa7127.c +++ b/drivers/media/video/saa7127.c | |||
@@ -53,7 +53,7 @@ | |||
53 | #include <linux/slab.h> | 53 | #include <linux/slab.h> |
54 | #include <linux/i2c.h> | 54 | #include <linux/i2c.h> |
55 | #include <linux/videodev2.h> | 55 | #include <linux/videodev2.h> |
56 | #include <media/v4l2-common.h> | 56 | #include <media/v4l2-device.h> |
57 | #include <media/v4l2-chip-ident.h> | 57 | #include <media/v4l2-chip-ident.h> |
58 | #include <media/v4l2-i2c-drv.h> | 58 | #include <media/v4l2-i2c-drv.h> |
59 | #include <media/saa7127.h> | 59 | #include <media/saa7127.h> |
@@ -231,6 +231,7 @@ static struct i2c_reg_value saa7127_init_config_50hz[] = { | |||
231 | */ | 231 | */ |
232 | 232 | ||
233 | struct saa7127_state { | 233 | struct saa7127_state { |
234 | struct v4l2_subdev sd; | ||
234 | v4l2_std_id std; | 235 | v4l2_std_id std; |
235 | u32 ident; | 236 | u32 ident; |
236 | enum saa7127_input_type input_type; | 237 | enum saa7127_input_type input_type; |
@@ -250,6 +251,11 @@ struct saa7127_state { | |||
250 | u8 reg_61; | 251 | u8 reg_61; |
251 | }; | 252 | }; |
252 | 253 | ||
254 | static inline struct saa7127_state *to_state(struct v4l2_subdev *sd) | ||
255 | { | ||
256 | return container_of(sd, struct saa7127_state, sd); | ||
257 | } | ||
258 | |||
253 | static const char * const output_strs[] = | 259 | static const char * const output_strs[] = |
254 | { | 260 | { |
255 | "S-Video + Composite", | 261 | "S-Video + Composite", |
@@ -281,32 +287,35 @@ static const char * const wss_strs[] = { | |||
281 | 287 | ||
282 | /* ----------------------------------------------------------------------- */ | 288 | /* ----------------------------------------------------------------------- */ |
283 | 289 | ||
284 | static int saa7127_read(struct i2c_client *client, u8 reg) | 290 | static int saa7127_read(struct v4l2_subdev *sd, u8 reg) |
285 | { | 291 | { |
292 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
293 | |||
286 | return i2c_smbus_read_byte_data(client, reg); | 294 | return i2c_smbus_read_byte_data(client, reg); |
287 | } | 295 | } |
288 | 296 | ||
289 | /* ----------------------------------------------------------------------- */ | 297 | /* ----------------------------------------------------------------------- */ |
290 | 298 | ||
291 | static int saa7127_write(struct i2c_client *client, u8 reg, u8 val) | 299 | static int saa7127_write(struct v4l2_subdev *sd, u8 reg, u8 val) |
292 | { | 300 | { |
301 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
293 | int i; | 302 | int i; |
294 | 303 | ||
295 | for (i = 0; i < 3; i++) { | 304 | for (i = 0; i < 3; i++) { |
296 | if (i2c_smbus_write_byte_data(client, reg, val) == 0) | 305 | if (i2c_smbus_write_byte_data(client, reg, val) == 0) |
297 | return 0; | 306 | return 0; |
298 | } | 307 | } |
299 | v4l_err(client, "I2C Write Problem\n"); | 308 | v4l2_err(sd, "I2C Write Problem\n"); |
300 | return -1; | 309 | return -1; |
301 | } | 310 | } |
302 | 311 | ||
303 | /* ----------------------------------------------------------------------- */ | 312 | /* ----------------------------------------------------------------------- */ |
304 | 313 | ||
305 | static int saa7127_write_inittab(struct i2c_client *client, | 314 | static int saa7127_write_inittab(struct v4l2_subdev *sd, |
306 | const struct i2c_reg_value *regs) | 315 | const struct i2c_reg_value *regs) |
307 | { | 316 | { |
308 | while (regs->reg != 0) { | 317 | while (regs->reg != 0) { |
309 | saa7127_write(client, regs->reg, regs->value); | 318 | saa7127_write(sd, regs->reg, regs->value); |
310 | regs++; | 319 | regs++; |
311 | } | 320 | } |
312 | return 0; | 321 | return 0; |
@@ -314,16 +323,16 @@ static int saa7127_write_inittab(struct i2c_client *client, | |||
314 | 323 | ||
315 | /* ----------------------------------------------------------------------- */ | 324 | /* ----------------------------------------------------------------------- */ |
316 | 325 | ||
317 | static int saa7127_set_vps(struct i2c_client *client, struct v4l2_sliced_vbi_data *data) | 326 | static int saa7127_set_vps(struct v4l2_subdev *sd, const struct v4l2_sliced_vbi_data *data) |
318 | { | 327 | { |
319 | struct saa7127_state *state = i2c_get_clientdata(client); | 328 | struct saa7127_state *state = to_state(sd); |
320 | int enable = (data->line != 0); | 329 | int enable = (data->line != 0); |
321 | 330 | ||
322 | if (enable && (data->field != 0 || data->line != 16)) | 331 | if (enable && (data->field != 0 || data->line != 16)) |
323 | return -EINVAL; | 332 | return -EINVAL; |
324 | if (state->vps_enable != enable) { | 333 | if (state->vps_enable != enable) { |
325 | v4l_dbg(1, debug, client, "Turn VPS Signal %s\n", enable ? "on" : "off"); | 334 | v4l2_dbg(1, debug, sd, "Turn VPS Signal %s\n", enable ? "on" : "off"); |
326 | saa7127_write(client, 0x54, enable << 7); | 335 | saa7127_write(sd, 0x54, enable << 7); |
327 | state->vps_enable = enable; | 336 | state->vps_enable = enable; |
328 | } | 337 | } |
329 | if (!enable) | 338 | if (!enable) |
@@ -334,91 +343,91 @@ static int saa7127_set_vps(struct i2c_client *client, struct v4l2_sliced_vbi_dat | |||
334 | state->vps_data[2] = data->data[9]; | 343 | state->vps_data[2] = data->data[9]; |
335 | state->vps_data[3] = data->data[10]; | 344 | state->vps_data[3] = data->data[10]; |
336 | state->vps_data[4] = data->data[11]; | 345 | state->vps_data[4] = data->data[11]; |
337 | v4l_dbg(1, debug, client, "Set VPS data %02x %02x %02x %02x %02x\n", | 346 | v4l2_dbg(1, debug, sd, "Set VPS data %02x %02x %02x %02x %02x\n", |
338 | state->vps_data[0], state->vps_data[1], | 347 | state->vps_data[0], state->vps_data[1], |
339 | state->vps_data[2], state->vps_data[3], | 348 | state->vps_data[2], state->vps_data[3], |
340 | state->vps_data[4]); | 349 | state->vps_data[4]); |
341 | saa7127_write(client, 0x55, state->vps_data[0]); | 350 | saa7127_write(sd, 0x55, state->vps_data[0]); |
342 | saa7127_write(client, 0x56, state->vps_data[1]); | 351 | saa7127_write(sd, 0x56, state->vps_data[1]); |
343 | saa7127_write(client, 0x57, state->vps_data[2]); | 352 | saa7127_write(sd, 0x57, state->vps_data[2]); |
344 | saa7127_write(client, 0x58, state->vps_data[3]); | 353 | saa7127_write(sd, 0x58, state->vps_data[3]); |
345 | saa7127_write(client, 0x59, state->vps_data[4]); | 354 | saa7127_write(sd, 0x59, state->vps_data[4]); |
346 | return 0; | 355 | return 0; |
347 | } | 356 | } |
348 | 357 | ||
349 | /* ----------------------------------------------------------------------- */ | 358 | /* ----------------------------------------------------------------------- */ |
350 | 359 | ||
351 | static int saa7127_set_cc(struct i2c_client *client, struct v4l2_sliced_vbi_data *data) | 360 | static int saa7127_set_cc(struct v4l2_subdev *sd, const struct v4l2_sliced_vbi_data *data) |
352 | { | 361 | { |
353 | struct saa7127_state *state = i2c_get_clientdata(client); | 362 | struct saa7127_state *state = to_state(sd); |
354 | u16 cc = data->data[1] << 8 | data->data[0]; | 363 | u16 cc = data->data[1] << 8 | data->data[0]; |
355 | int enable = (data->line != 0); | 364 | int enable = (data->line != 0); |
356 | 365 | ||
357 | if (enable && (data->field != 0 || data->line != 21)) | 366 | if (enable && (data->field != 0 || data->line != 21)) |
358 | return -EINVAL; | 367 | return -EINVAL; |
359 | if (state->cc_enable != enable) { | 368 | if (state->cc_enable != enable) { |
360 | v4l_dbg(1, debug, client, | 369 | v4l2_dbg(1, debug, sd, |
361 | "Turn CC %s\n", enable ? "on" : "off"); | 370 | "Turn CC %s\n", enable ? "on" : "off"); |
362 | saa7127_write(client, SAA7127_REG_CLOSED_CAPTION, | 371 | saa7127_write(sd, SAA7127_REG_CLOSED_CAPTION, |
363 | (state->xds_enable << 7) | (enable << 6) | 0x11); | 372 | (state->xds_enable << 7) | (enable << 6) | 0x11); |
364 | state->cc_enable = enable; | 373 | state->cc_enable = enable; |
365 | } | 374 | } |
366 | if (!enable) | 375 | if (!enable) |
367 | return 0; | 376 | return 0; |
368 | 377 | ||
369 | v4l_dbg(2, debug, client, "CC data: %04x\n", cc); | 378 | v4l2_dbg(2, debug, sd, "CC data: %04x\n", cc); |
370 | saa7127_write(client, SAA7127_REG_LINE_21_ODD_0, cc & 0xff); | 379 | saa7127_write(sd, SAA7127_REG_LINE_21_ODD_0, cc & 0xff); |
371 | saa7127_write(client, SAA7127_REG_LINE_21_ODD_1, cc >> 8); | 380 | saa7127_write(sd, SAA7127_REG_LINE_21_ODD_1, cc >> 8); |
372 | state->cc_data = cc; | 381 | state->cc_data = cc; |
373 | return 0; | 382 | return 0; |
374 | } | 383 | } |
375 | 384 | ||
376 | /* ----------------------------------------------------------------------- */ | 385 | /* ----------------------------------------------------------------------- */ |
377 | 386 | ||
378 | static int saa7127_set_xds(struct i2c_client *client, struct v4l2_sliced_vbi_data *data) | 387 | static int saa7127_set_xds(struct v4l2_subdev *sd, const struct v4l2_sliced_vbi_data *data) |
379 | { | 388 | { |
380 | struct saa7127_state *state = i2c_get_clientdata(client); | 389 | struct saa7127_state *state = to_state(sd); |
381 | u16 xds = data->data[1] << 8 | data->data[0]; | 390 | u16 xds = data->data[1] << 8 | data->data[0]; |
382 | int enable = (data->line != 0); | 391 | int enable = (data->line != 0); |
383 | 392 | ||
384 | if (enable && (data->field != 1 || data->line != 21)) | 393 | if (enable && (data->field != 1 || data->line != 21)) |
385 | return -EINVAL; | 394 | return -EINVAL; |
386 | if (state->xds_enable != enable) { | 395 | if (state->xds_enable != enable) { |
387 | v4l_dbg(1, debug, client, "Turn XDS %s\n", enable ? "on" : "off"); | 396 | v4l2_dbg(1, debug, sd, "Turn XDS %s\n", enable ? "on" : "off"); |
388 | saa7127_write(client, SAA7127_REG_CLOSED_CAPTION, | 397 | saa7127_write(sd, SAA7127_REG_CLOSED_CAPTION, |
389 | (enable << 7) | (state->cc_enable << 6) | 0x11); | 398 | (enable << 7) | (state->cc_enable << 6) | 0x11); |
390 | state->xds_enable = enable; | 399 | state->xds_enable = enable; |
391 | } | 400 | } |
392 | if (!enable) | 401 | if (!enable) |
393 | return 0; | 402 | return 0; |
394 | 403 | ||
395 | v4l_dbg(2, debug, client, "XDS data: %04x\n", xds); | 404 | v4l2_dbg(2, debug, sd, "XDS data: %04x\n", xds); |
396 | saa7127_write(client, SAA7127_REG_LINE_21_EVEN_0, xds & 0xff); | 405 | saa7127_write(sd, SAA7127_REG_LINE_21_EVEN_0, xds & 0xff); |
397 | saa7127_write(client, SAA7127_REG_LINE_21_EVEN_1, xds >> 8); | 406 | saa7127_write(sd, SAA7127_REG_LINE_21_EVEN_1, xds >> 8); |
398 | state->xds_data = xds; | 407 | state->xds_data = xds; |
399 | return 0; | 408 | return 0; |
400 | } | 409 | } |
401 | 410 | ||
402 | /* ----------------------------------------------------------------------- */ | 411 | /* ----------------------------------------------------------------------- */ |
403 | 412 | ||
404 | static int saa7127_set_wss(struct i2c_client *client, struct v4l2_sliced_vbi_data *data) | 413 | static int saa7127_set_wss(struct v4l2_subdev *sd, const struct v4l2_sliced_vbi_data *data) |
405 | { | 414 | { |
406 | struct saa7127_state *state = i2c_get_clientdata(client); | 415 | struct saa7127_state *state = to_state(sd); |
407 | int enable = (data->line != 0); | 416 | int enable = (data->line != 0); |
408 | 417 | ||
409 | if (enable && (data->field != 0 || data->line != 23)) | 418 | if (enable && (data->field != 0 || data->line != 23)) |
410 | return -EINVAL; | 419 | return -EINVAL; |
411 | if (state->wss_enable != enable) { | 420 | if (state->wss_enable != enable) { |
412 | v4l_dbg(1, debug, client, "Turn WSS %s\n", enable ? "on" : "off"); | 421 | v4l2_dbg(1, debug, sd, "Turn WSS %s\n", enable ? "on" : "off"); |
413 | saa7127_write(client, 0x27, enable << 7); | 422 | saa7127_write(sd, 0x27, enable << 7); |
414 | state->wss_enable = enable; | 423 | state->wss_enable = enable; |
415 | } | 424 | } |
416 | if (!enable) | 425 | if (!enable) |
417 | return 0; | 426 | return 0; |
418 | 427 | ||
419 | saa7127_write(client, 0x26, data->data[0]); | 428 | saa7127_write(sd, 0x26, data->data[0]); |
420 | saa7127_write(client, 0x27, 0x80 | (data->data[1] & 0x3f)); | 429 | saa7127_write(sd, 0x27, 0x80 | (data->data[1] & 0x3f)); |
421 | v4l_dbg(1, debug, client, | 430 | v4l2_dbg(1, debug, sd, |
422 | "WSS mode: %s\n", wss_strs[data->data[0] & 0xf]); | 431 | "WSS mode: %s\n", wss_strs[data->data[0] & 0xf]); |
423 | state->wss_mode = (data->data[1] & 0x3f) << 8 | data->data[0]; | 432 | state->wss_mode = (data->data[1] & 0x3f) << 8 | data->data[0]; |
424 | return 0; | 433 | return 0; |
@@ -426,18 +435,18 @@ static int saa7127_set_wss(struct i2c_client *client, struct v4l2_sliced_vbi_dat | |||
426 | 435 | ||
427 | /* ----------------------------------------------------------------------- */ | 436 | /* ----------------------------------------------------------------------- */ |
428 | 437 | ||
429 | static int saa7127_set_video_enable(struct i2c_client *client, int enable) | 438 | static int saa7127_set_video_enable(struct v4l2_subdev *sd, int enable) |
430 | { | 439 | { |
431 | struct saa7127_state *state = i2c_get_clientdata(client); | 440 | struct saa7127_state *state = to_state(sd); |
432 | 441 | ||
433 | if (enable) { | 442 | if (enable) { |
434 | v4l_dbg(1, debug, client, "Enable Video Output\n"); | 443 | v4l2_dbg(1, debug, sd, "Enable Video Output\n"); |
435 | saa7127_write(client, 0x2d, state->reg_2d); | 444 | saa7127_write(sd, 0x2d, state->reg_2d); |
436 | saa7127_write(client, 0x61, state->reg_61); | 445 | saa7127_write(sd, 0x61, state->reg_61); |
437 | } else { | 446 | } else { |
438 | v4l_dbg(1, debug, client, "Disable Video Output\n"); | 447 | v4l2_dbg(1, debug, sd, "Disable Video Output\n"); |
439 | saa7127_write(client, 0x2d, (state->reg_2d & 0xf0)); | 448 | saa7127_write(sd, 0x2d, (state->reg_2d & 0xf0)); |
440 | saa7127_write(client, 0x61, (state->reg_61 | 0xc0)); | 449 | saa7127_write(sd, 0x61, (state->reg_61 | 0xc0)); |
441 | } | 450 | } |
442 | state->video_enable = enable; | 451 | state->video_enable = enable; |
443 | return 0; | 452 | return 0; |
@@ -445,32 +454,32 @@ static int saa7127_set_video_enable(struct i2c_client *client, int enable) | |||
445 | 454 | ||
446 | /* ----------------------------------------------------------------------- */ | 455 | /* ----------------------------------------------------------------------- */ |
447 | 456 | ||
448 | static int saa7127_set_std(struct i2c_client *client, v4l2_std_id std) | 457 | static int saa7127_set_std(struct v4l2_subdev *sd, v4l2_std_id std) |
449 | { | 458 | { |
450 | struct saa7127_state *state = i2c_get_clientdata(client); | 459 | struct saa7127_state *state = to_state(sd); |
451 | const struct i2c_reg_value *inittab; | 460 | const struct i2c_reg_value *inittab; |
452 | 461 | ||
453 | if (std & V4L2_STD_525_60) { | 462 | if (std & V4L2_STD_525_60) { |
454 | v4l_dbg(1, debug, client, "Selecting 60 Hz video Standard\n"); | 463 | v4l2_dbg(1, debug, sd, "Selecting 60 Hz video Standard\n"); |
455 | inittab = saa7127_init_config_60hz; | 464 | inittab = saa7127_init_config_60hz; |
456 | state->reg_61 = SAA7127_60HZ_DAC_CONTROL; | 465 | state->reg_61 = SAA7127_60HZ_DAC_CONTROL; |
457 | } else { | 466 | } else { |
458 | v4l_dbg(1, debug, client, "Selecting 50 Hz video Standard\n"); | 467 | v4l2_dbg(1, debug, sd, "Selecting 50 Hz video Standard\n"); |
459 | inittab = saa7127_init_config_50hz; | 468 | inittab = saa7127_init_config_50hz; |
460 | state->reg_61 = SAA7127_50HZ_DAC_CONTROL; | 469 | state->reg_61 = SAA7127_50HZ_DAC_CONTROL; |
461 | } | 470 | } |
462 | 471 | ||
463 | /* Write Table */ | 472 | /* Write Table */ |
464 | saa7127_write_inittab(client, inittab); | 473 | saa7127_write_inittab(sd, inittab); |
465 | state->std = std; | 474 | state->std = std; |
466 | return 0; | 475 | return 0; |
467 | } | 476 | } |
468 | 477 | ||
469 | /* ----------------------------------------------------------------------- */ | 478 | /* ----------------------------------------------------------------------- */ |
470 | 479 | ||
471 | static int saa7127_set_output_type(struct i2c_client *client, int output) | 480 | static int saa7127_set_output_type(struct v4l2_subdev *sd, int output) |
472 | { | 481 | { |
473 | struct saa7127_state *state = i2c_get_clientdata(client); | 482 | struct saa7127_state *state = to_state(sd); |
474 | 483 | ||
475 | switch (output) { | 484 | switch (output) { |
476 | case SAA7127_OUTPUT_TYPE_RGB: | 485 | case SAA7127_OUTPUT_TYPE_RGB: |
@@ -506,165 +515,195 @@ static int saa7127_set_output_type(struct i2c_client *client, int output) | |||
506 | default: | 515 | default: |
507 | return -EINVAL; | 516 | return -EINVAL; |
508 | } | 517 | } |
509 | v4l_dbg(1, debug, client, | 518 | v4l2_dbg(1, debug, sd, |
510 | "Selecting %s output type\n", output_strs[output]); | 519 | "Selecting %s output type\n", output_strs[output]); |
511 | 520 | ||
512 | /* Configure Encoder */ | 521 | /* Configure Encoder */ |
513 | saa7127_write(client, 0x2d, state->reg_2d); | 522 | saa7127_write(sd, 0x2d, state->reg_2d); |
514 | saa7127_write(client, 0x3a, state->reg_3a | state->reg_3a_cb); | 523 | saa7127_write(sd, 0x3a, state->reg_3a | state->reg_3a_cb); |
515 | state->output_type = output; | 524 | state->output_type = output; |
516 | return 0; | 525 | return 0; |
517 | } | 526 | } |
518 | 527 | ||
519 | /* ----------------------------------------------------------------------- */ | 528 | /* ----------------------------------------------------------------------- */ |
520 | 529 | ||
521 | static int saa7127_set_input_type(struct i2c_client *client, int input) | 530 | static int saa7127_set_input_type(struct v4l2_subdev *sd, int input) |
522 | { | 531 | { |
523 | struct saa7127_state *state = i2c_get_clientdata(client); | 532 | struct saa7127_state *state = to_state(sd); |
524 | 533 | ||
525 | switch (input) { | 534 | switch (input) { |
526 | case SAA7127_INPUT_TYPE_NORMAL: /* avia */ | 535 | case SAA7127_INPUT_TYPE_NORMAL: /* avia */ |
527 | v4l_dbg(1, debug, client, "Selecting Normal Encoder Input\n"); | 536 | v4l2_dbg(1, debug, sd, "Selecting Normal Encoder Input\n"); |
528 | state->reg_3a_cb = 0; | 537 | state->reg_3a_cb = 0; |
529 | break; | 538 | break; |
530 | 539 | ||
531 | case SAA7127_INPUT_TYPE_TEST_IMAGE: /* color bar */ | 540 | case SAA7127_INPUT_TYPE_TEST_IMAGE: /* color bar */ |
532 | v4l_dbg(1, debug, client, "Selecting Color Bar generator\n"); | 541 | v4l2_dbg(1, debug, sd, "Selecting Color Bar generator\n"); |
533 | state->reg_3a_cb = 0x80; | 542 | state->reg_3a_cb = 0x80; |
534 | break; | 543 | break; |
535 | 544 | ||
536 | default: | 545 | default: |
537 | return -EINVAL; | 546 | return -EINVAL; |
538 | } | 547 | } |
539 | saa7127_write(client, 0x3a, state->reg_3a | state->reg_3a_cb); | 548 | saa7127_write(sd, 0x3a, state->reg_3a | state->reg_3a_cb); |
540 | state->input_type = input; | 549 | state->input_type = input; |
541 | return 0; | 550 | return 0; |
542 | } | 551 | } |
543 | 552 | ||
544 | /* ----------------------------------------------------------------------- */ | 553 | /* ----------------------------------------------------------------------- */ |
545 | 554 | ||
546 | static int saa7127_command(struct i2c_client *client, | 555 | static int saa7127_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std) |
547 | unsigned int cmd, void *arg) | ||
548 | { | 556 | { |
549 | struct saa7127_state *state = i2c_get_clientdata(client); | 557 | struct saa7127_state *state = to_state(sd); |
550 | struct v4l2_format *fmt = arg; | ||
551 | struct v4l2_routing *route = arg; | ||
552 | |||
553 | switch (cmd) { | ||
554 | case VIDIOC_INT_S_STD_OUTPUT: | ||
555 | if (state->std == *(v4l2_std_id *)arg) | ||
556 | break; | ||
557 | return saa7127_set_std(client, *(v4l2_std_id *)arg); | ||
558 | |||
559 | case VIDIOC_INT_G_STD_OUTPUT: | ||
560 | *(v4l2_std_id *)arg = state->std; | ||
561 | break; | ||
562 | 558 | ||
563 | case VIDIOC_INT_G_VIDEO_ROUTING: | 559 | if (state->std == std) |
564 | route->input = state->input_type; | 560 | return 0; |
565 | route->output = state->output_type; | 561 | return saa7127_set_std(sd, std); |
566 | break; | 562 | } |
567 | 563 | ||
568 | case VIDIOC_INT_S_VIDEO_ROUTING: | 564 | static int saa7127_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route) |
569 | { | 565 | { |
570 | int rc = 0; | 566 | struct saa7127_state *state = to_state(sd); |
567 | int rc = 0; | ||
568 | |||
569 | if (state->input_type != route->input) | ||
570 | rc = saa7127_set_input_type(sd, route->input); | ||
571 | if (rc == 0 && state->output_type != route->output) | ||
572 | rc = saa7127_set_output_type(sd, route->output); | ||
573 | return rc; | ||
574 | } | ||
571 | 575 | ||
572 | if (state->input_type != route->input) | 576 | static int saa7127_s_stream(struct v4l2_subdev *sd, int enable) |
573 | rc = saa7127_set_input_type(client, route->input); | 577 | { |
574 | if (rc == 0 && state->output_type != route->output) | 578 | struct saa7127_state *state = to_state(sd); |
575 | rc = saa7127_set_output_type(client, route->output); | ||
576 | return rc; | ||
577 | } | ||
578 | 579 | ||
579 | case VIDIOC_STREAMON: | 580 | if (state->video_enable == enable) |
580 | case VIDIOC_STREAMOFF: | 581 | return 0; |
581 | if (state->video_enable == (cmd == VIDIOC_STREAMON)) | 582 | return saa7127_set_video_enable(sd, enable); |
582 | break; | 583 | } |
583 | return saa7127_set_video_enable(client, cmd == VIDIOC_STREAMON); | ||
584 | |||
585 | case VIDIOC_G_FMT: | ||
586 | if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) | ||
587 | return -EINVAL; | ||
588 | |||
589 | memset(&fmt->fmt.sliced, 0, sizeof(fmt->fmt.sliced)); | ||
590 | if (state->vps_enable) | ||
591 | fmt->fmt.sliced.service_lines[0][16] = V4L2_SLICED_VPS; | ||
592 | if (state->wss_enable) | ||
593 | fmt->fmt.sliced.service_lines[0][23] = V4L2_SLICED_WSS_625; | ||
594 | if (state->cc_enable) { | ||
595 | fmt->fmt.sliced.service_lines[0][21] = V4L2_SLICED_CAPTION_525; | ||
596 | fmt->fmt.sliced.service_lines[1][21] = V4L2_SLICED_CAPTION_525; | ||
597 | } | ||
598 | fmt->fmt.sliced.service_set = | ||
599 | (state->vps_enable ? V4L2_SLICED_VPS : 0) | | ||
600 | (state->wss_enable ? V4L2_SLICED_WSS_625 : 0) | | ||
601 | (state->cc_enable ? V4L2_SLICED_CAPTION_525 : 0); | ||
602 | break; | ||
603 | 584 | ||
604 | case VIDIOC_LOG_STATUS: | 585 | static int saa7127_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt) |
605 | v4l_info(client, "Standard: %s\n", (state->std & V4L2_STD_525_60) ? "60 Hz" : "50 Hz"); | 586 | { |
606 | v4l_info(client, "Input: %s\n", state->input_type ? "color bars" : "normal"); | 587 | struct saa7127_state *state = to_state(sd); |
607 | v4l_info(client, "Output: %s\n", state->video_enable ? | ||
608 | output_strs[state->output_type] : "disabled"); | ||
609 | v4l_info(client, "WSS: %s\n", state->wss_enable ? | ||
610 | wss_strs[state->wss_mode] : "disabled"); | ||
611 | v4l_info(client, "VPS: %s\n", state->vps_enable ? "enabled" : "disabled"); | ||
612 | v4l_info(client, "CC: %s\n", state->cc_enable ? "enabled" : "disabled"); | ||
613 | break; | ||
614 | 588 | ||
615 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 589 | if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) |
616 | case VIDIOC_DBG_G_REGISTER: | 590 | return -EINVAL; |
617 | case VIDIOC_DBG_S_REGISTER: | ||
618 | { | ||
619 | struct v4l2_register *reg = arg; | ||
620 | |||
621 | if (!v4l2_chip_match_i2c_client(client, | ||
622 | reg->match_type, reg->match_chip)) | ||
623 | return -EINVAL; | ||
624 | if (!capable(CAP_SYS_ADMIN)) | ||
625 | return -EPERM; | ||
626 | if (cmd == VIDIOC_DBG_G_REGISTER) | ||
627 | reg->val = saa7127_read(client, reg->reg & 0xff); | ||
628 | else | ||
629 | saa7127_write(client, reg->reg & 0xff, reg->val & 0xff); | ||
630 | break; | ||
631 | } | ||
632 | #endif | ||
633 | 591 | ||
634 | case VIDIOC_INT_S_VBI_DATA: | 592 | memset(&fmt->fmt.sliced, 0, sizeof(fmt->fmt.sliced)); |
635 | { | 593 | if (state->vps_enable) |
636 | struct v4l2_sliced_vbi_data *data = arg; | 594 | fmt->fmt.sliced.service_lines[0][16] = V4L2_SLICED_VPS; |
637 | 595 | if (state->wss_enable) | |
638 | switch (data->id) { | 596 | fmt->fmt.sliced.service_lines[0][23] = V4L2_SLICED_WSS_625; |
639 | case V4L2_SLICED_WSS_625: | 597 | if (state->cc_enable) { |
640 | return saa7127_set_wss(client, data); | 598 | fmt->fmt.sliced.service_lines[0][21] = V4L2_SLICED_CAPTION_525; |
641 | case V4L2_SLICED_VPS: | 599 | fmt->fmt.sliced.service_lines[1][21] = V4L2_SLICED_CAPTION_525; |
642 | return saa7127_set_vps(client, data); | ||
643 | case V4L2_SLICED_CAPTION_525: | ||
644 | if (data->field == 0) | ||
645 | return saa7127_set_cc(client, data); | ||
646 | return saa7127_set_xds(client, data); | ||
647 | default: | ||
648 | return -EINVAL; | ||
649 | } | ||
650 | break; | ||
651 | } | 600 | } |
601 | fmt->fmt.sliced.service_set = | ||
602 | (state->vps_enable ? V4L2_SLICED_VPS : 0) | | ||
603 | (state->wss_enable ? V4L2_SLICED_WSS_625 : 0) | | ||
604 | (state->cc_enable ? V4L2_SLICED_CAPTION_525 : 0); | ||
605 | return 0; | ||
606 | } | ||
652 | 607 | ||
653 | case VIDIOC_G_CHIP_IDENT: | 608 | static int saa7127_s_vbi_data(struct v4l2_subdev *sd, const struct v4l2_sliced_vbi_data *data) |
654 | return v4l2_chip_ident_i2c_client(client, arg, state->ident, 0); | 609 | { |
655 | 610 | switch (data->id) { | |
611 | case V4L2_SLICED_WSS_625: | ||
612 | return saa7127_set_wss(sd, data); | ||
613 | case V4L2_SLICED_VPS: | ||
614 | return saa7127_set_vps(sd, data); | ||
615 | case V4L2_SLICED_CAPTION_525: | ||
616 | if (data->field == 0) | ||
617 | return saa7127_set_cc(sd, data); | ||
618 | return saa7127_set_xds(sd, data); | ||
656 | default: | 619 | default: |
657 | return -EINVAL; | 620 | return -EINVAL; |
658 | } | 621 | } |
659 | return 0; | 622 | return 0; |
660 | } | 623 | } |
661 | 624 | ||
625 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
626 | static int saa7127_g_register(struct v4l2_subdev *sd, struct v4l2_register *reg) | ||
627 | { | ||
628 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
629 | |||
630 | if (!v4l2_chip_match_i2c_client(client, | ||
631 | reg->match_type, reg->match_chip)) | ||
632 | return -EINVAL; | ||
633 | if (!capable(CAP_SYS_ADMIN)) | ||
634 | return -EPERM; | ||
635 | reg->val = saa7127_read(sd, reg->reg & 0xff); | ||
636 | return 0; | ||
637 | } | ||
638 | |||
639 | static int saa7127_s_register(struct v4l2_subdev *sd, struct v4l2_register *reg) | ||
640 | { | ||
641 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
642 | |||
643 | if (!v4l2_chip_match_i2c_client(client, | ||
644 | reg->match_type, reg->match_chip)) | ||
645 | return -EINVAL; | ||
646 | if (!capable(CAP_SYS_ADMIN)) | ||
647 | return -EPERM; | ||
648 | saa7127_write(sd, reg->reg & 0xff, reg->val & 0xff); | ||
649 | return 0; | ||
650 | } | ||
651 | #endif | ||
652 | |||
653 | static int saa7127_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_chip_ident *chip) | ||
654 | { | ||
655 | struct saa7127_state *state = to_state(sd); | ||
656 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
657 | |||
658 | return v4l2_chip_ident_i2c_client(client, chip, state->ident, 0); | ||
659 | } | ||
660 | |||
661 | static int saa7127_log_status(struct v4l2_subdev *sd) | ||
662 | { | ||
663 | struct saa7127_state *state = to_state(sd); | ||
664 | |||
665 | v4l2_info(sd, "Standard: %s\n", (state->std & V4L2_STD_525_60) ? "60 Hz" : "50 Hz"); | ||
666 | v4l2_info(sd, "Input: %s\n", state->input_type ? "color bars" : "normal"); | ||
667 | v4l2_info(sd, "Output: %s\n", state->video_enable ? | ||
668 | output_strs[state->output_type] : "disabled"); | ||
669 | v4l2_info(sd, "WSS: %s\n", state->wss_enable ? | ||
670 | wss_strs[state->wss_mode] : "disabled"); | ||
671 | v4l2_info(sd, "VPS: %s\n", state->vps_enable ? "enabled" : "disabled"); | ||
672 | v4l2_info(sd, "CC: %s\n", state->cc_enable ? "enabled" : "disabled"); | ||
673 | return 0; | ||
674 | } | ||
675 | |||
676 | /* ----------------------------------------------------------------------- */ | ||
677 | |||
678 | static const struct v4l2_subdev_core_ops saa7127_core_ops = { | ||
679 | .log_status = saa7127_log_status, | ||
680 | .g_chip_ident = saa7127_g_chip_ident, | ||
681 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
682 | .g_register = saa7127_g_register, | ||
683 | .s_register = saa7127_s_register, | ||
684 | #endif | ||
685 | }; | ||
686 | |||
687 | static const struct v4l2_subdev_video_ops saa7127_video_ops = { | ||
688 | .s_vbi_data = saa7127_s_vbi_data, | ||
689 | .g_fmt = saa7127_g_fmt, | ||
690 | .s_std_output = saa7127_s_std_output, | ||
691 | .s_routing = saa7127_s_routing, | ||
692 | .s_stream = saa7127_s_stream, | ||
693 | }; | ||
694 | |||
695 | static const struct v4l2_subdev_ops saa7127_ops = { | ||
696 | .core = &saa7127_core_ops, | ||
697 | .video = &saa7127_video_ops, | ||
698 | }; | ||
699 | |||
662 | /* ----------------------------------------------------------------------- */ | 700 | /* ----------------------------------------------------------------------- */ |
663 | 701 | ||
664 | static int saa7127_probe(struct i2c_client *client, | 702 | static int saa7127_probe(struct i2c_client *client, |
665 | const struct i2c_device_id *id) | 703 | const struct i2c_device_id *id) |
666 | { | 704 | { |
667 | struct saa7127_state *state; | 705 | struct saa7127_state *state; |
706 | struct v4l2_subdev *sd; | ||
668 | struct v4l2_sliced_vbi_data vbi = { 0, 0, 0, 0 }; /* set to disabled */ | 707 | struct v4l2_sliced_vbi_data vbi = { 0, 0, 0, 0 }; /* set to disabled */ |
669 | 708 | ||
670 | /* Check if the adapter supports the needed features */ | 709 | /* Check if the adapter supports the needed features */ |
@@ -674,40 +713,42 @@ static int saa7127_probe(struct i2c_client *client, | |||
674 | v4l_dbg(1, debug, client, "detecting saa7127 client on address 0x%x\n", | 713 | v4l_dbg(1, debug, client, "detecting saa7127 client on address 0x%x\n", |
675 | client->addr << 1); | 714 | client->addr << 1); |
676 | 715 | ||
716 | state = kzalloc(sizeof(struct saa7127_state), GFP_KERNEL); | ||
717 | if (state == NULL) | ||
718 | return -ENOMEM; | ||
719 | |||
720 | sd = &state->sd; | ||
721 | v4l2_i2c_subdev_init(sd, client, &saa7127_ops); | ||
722 | |||
677 | /* First test register 0: Bits 5-7 are a version ID (should be 0), | 723 | /* First test register 0: Bits 5-7 are a version ID (should be 0), |
678 | and bit 2 should also be 0. | 724 | and bit 2 should also be 0. |
679 | This is rather general, so the second test is more specific and | 725 | This is rather general, so the second test is more specific and |
680 | looks at the 'ending point of burst in clock cycles' which is | 726 | looks at the 'ending point of burst in clock cycles' which is |
681 | 0x1d after a reset and not expected to ever change. */ | 727 | 0x1d after a reset and not expected to ever change. */ |
682 | if ((saa7127_read(client, 0) & 0xe4) != 0 || | 728 | if ((saa7127_read(sd, 0) & 0xe4) != 0 || |
683 | (saa7127_read(client, 0x29) & 0x3f) != 0x1d) { | 729 | (saa7127_read(sd, 0x29) & 0x3f) != 0x1d) { |
684 | v4l_dbg(1, debug, client, "saa7127 not found\n"); | 730 | v4l2_dbg(1, debug, sd, "saa7127 not found\n"); |
731 | kfree(state); | ||
685 | return -ENODEV; | 732 | return -ENODEV; |
686 | } | 733 | } |
687 | state = kzalloc(sizeof(struct saa7127_state), GFP_KERNEL); | ||
688 | |||
689 | if (state == NULL) | ||
690 | return -ENOMEM; | ||
691 | |||
692 | i2c_set_clientdata(client, state); | ||
693 | 734 | ||
694 | /* Configure Encoder */ | 735 | /* Configure Encoder */ |
695 | 736 | ||
696 | v4l_dbg(1, debug, client, "Configuring encoder\n"); | 737 | v4l2_dbg(1, debug, sd, "Configuring encoder\n"); |
697 | saa7127_write_inittab(client, saa7127_init_config_common); | 738 | saa7127_write_inittab(sd, saa7127_init_config_common); |
698 | saa7127_set_std(client, V4L2_STD_NTSC); | 739 | saa7127_set_std(sd, V4L2_STD_NTSC); |
699 | saa7127_set_output_type(client, SAA7127_OUTPUT_TYPE_BOTH); | 740 | saa7127_set_output_type(sd, SAA7127_OUTPUT_TYPE_BOTH); |
700 | saa7127_set_vps(client, &vbi); | 741 | saa7127_set_vps(sd, &vbi); |
701 | saa7127_set_wss(client, &vbi); | 742 | saa7127_set_wss(sd, &vbi); |
702 | saa7127_set_cc(client, &vbi); | 743 | saa7127_set_cc(sd, &vbi); |
703 | saa7127_set_xds(client, &vbi); | 744 | saa7127_set_xds(sd, &vbi); |
704 | if (test_image == 1) | 745 | if (test_image == 1) |
705 | /* The Encoder has an internal Colorbar generator */ | 746 | /* The Encoder has an internal Colorbar generator */ |
706 | /* This can be used for debugging */ | 747 | /* This can be used for debugging */ |
707 | saa7127_set_input_type(client, SAA7127_INPUT_TYPE_TEST_IMAGE); | 748 | saa7127_set_input_type(sd, SAA7127_INPUT_TYPE_TEST_IMAGE); |
708 | else | 749 | else |
709 | saa7127_set_input_type(client, SAA7127_INPUT_TYPE_NORMAL); | 750 | saa7127_set_input_type(sd, SAA7127_INPUT_TYPE_NORMAL); |
710 | saa7127_set_video_enable(client, 1); | 751 | saa7127_set_video_enable(sd, 1); |
711 | 752 | ||
712 | if (id->driver_data) { /* Chip type is already known */ | 753 | if (id->driver_data) { /* Chip type is already known */ |
713 | state->ident = id->driver_data; | 754 | state->ident = id->driver_data; |
@@ -715,10 +756,10 @@ static int saa7127_probe(struct i2c_client *client, | |||
715 | int read_result; | 756 | int read_result; |
716 | 757 | ||
717 | /* Detect if it's an saa7129 */ | 758 | /* Detect if it's an saa7129 */ |
718 | read_result = saa7127_read(client, SAA7129_REG_FADE_KEY_COL2); | 759 | read_result = saa7127_read(sd, SAA7129_REG_FADE_KEY_COL2); |
719 | saa7127_write(client, SAA7129_REG_FADE_KEY_COL2, 0xaa); | 760 | saa7127_write(sd, SAA7129_REG_FADE_KEY_COL2, 0xaa); |
720 | if (saa7127_read(client, SAA7129_REG_FADE_KEY_COL2) == 0xaa) { | 761 | if (saa7127_read(sd, SAA7129_REG_FADE_KEY_COL2) == 0xaa) { |
721 | saa7127_write(client, SAA7129_REG_FADE_KEY_COL2, | 762 | saa7127_write(sd, SAA7129_REG_FADE_KEY_COL2, |
722 | read_result); | 763 | read_result); |
723 | state->ident = V4L2_IDENT_SAA7129; | 764 | state->ident = V4L2_IDENT_SAA7129; |
724 | strlcpy(client->name, "saa7129", I2C_NAME_SIZE); | 765 | strlcpy(client->name, "saa7129", I2C_NAME_SIZE); |
@@ -728,10 +769,10 @@ static int saa7127_probe(struct i2c_client *client, | |||
728 | } | 769 | } |
729 | } | 770 | } |
730 | 771 | ||
731 | v4l_info(client, "%s found @ 0x%x (%s)\n", client->name, | 772 | v4l2_info(sd, "%s found @ 0x%x (%s)\n", client->name, |
732 | client->addr << 1, client->adapter->name); | 773 | client->addr << 1, client->adapter->name); |
733 | if (state->ident == V4L2_IDENT_SAA7129) | 774 | if (state->ident == V4L2_IDENT_SAA7129) |
734 | saa7127_write_inittab(client, saa7129_init_config_extra); | 775 | saa7127_write_inittab(sd, saa7129_init_config_extra); |
735 | return 0; | 776 | return 0; |
736 | } | 777 | } |
737 | 778 | ||
@@ -739,9 +780,12 @@ static int saa7127_probe(struct i2c_client *client, | |||
739 | 780 | ||
740 | static int saa7127_remove(struct i2c_client *client) | 781 | static int saa7127_remove(struct i2c_client *client) |
741 | { | 782 | { |
783 | struct v4l2_subdev *sd = i2c_get_clientdata(client); | ||
784 | |||
785 | v4l2_device_unregister_subdev(sd); | ||
742 | /* Turn off TV output */ | 786 | /* Turn off TV output */ |
743 | saa7127_set_video_enable(client, 0); | 787 | saa7127_set_video_enable(sd, 0); |
744 | kfree(i2c_get_clientdata(client)); | 788 | kfree(to_state(sd)); |
745 | return 0; | 789 | return 0; |
746 | } | 790 | } |
747 | 791 | ||
@@ -760,7 +804,6 @@ MODULE_DEVICE_TABLE(i2c, saa7127_id); | |||
760 | static struct v4l2_i2c_driver_data v4l2_i2c_data = { | 804 | static struct v4l2_i2c_driver_data v4l2_i2c_data = { |
761 | .name = "saa7127", | 805 | .name = "saa7127", |
762 | .driverid = I2C_DRIVERID_SAA7127, | 806 | .driverid = I2C_DRIVERID_SAA7127, |
763 | .command = saa7127_command, | ||
764 | .probe = saa7127_probe, | 807 | .probe = saa7127_probe, |
765 | .remove = saa7127_remove, | 808 | .remove = saa7127_remove, |
766 | .id_table = saa7127_id, | 809 | .id_table = saa7127_id, |