diff options
author | Hans Verkuil <hverkuil@xs4all.nl> | 2010-05-24 09:01:58 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2010-08-08 22:43:04 -0400 |
commit | ebc3bba5833e7021336f09767347a52448a60bc5 (patch) | |
tree | 02639770015eadf32693d6888ebfe29316df7e8d /drivers/media/video/msp3400-driver.c | |
parent | e356054337fe42a1b98725c8e68d6599764888b9 (diff) |
V4L/DVB: msp3400: convert to the new control framework
Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/msp3400-driver.c')
-rw-r--r-- | drivers/media/video/msp3400-driver.c | 248 |
1 files changed, 88 insertions, 160 deletions
diff --git a/drivers/media/video/msp3400-driver.c b/drivers/media/video/msp3400-driver.c index e9df3cb02cc1..0e412131da7c 100644 --- a/drivers/media/video/msp3400-driver.c +++ b/drivers/media/video/msp3400-driver.c | |||
@@ -283,51 +283,6 @@ void msp_set_scart(struct i2c_client *client, int in, int out) | |||
283 | msp_write_dem(client, 0x40, state->i2s_mode); | 283 | msp_write_dem(client, 0x40, state->i2s_mode); |
284 | } | 284 | } |
285 | 285 | ||
286 | void msp_set_audio(struct i2c_client *client) | ||
287 | { | ||
288 | struct msp_state *state = to_state(i2c_get_clientdata(client)); | ||
289 | int bal = 0, bass, treble, loudness; | ||
290 | int val = 0; | ||
291 | int reallymuted = state->muted | state->scan_in_progress; | ||
292 | |||
293 | if (!reallymuted) | ||
294 | val = (state->volume * 0x7f / 65535) << 8; | ||
295 | |||
296 | v4l_dbg(1, msp_debug, client, "mute=%s scanning=%s volume=%d\n", | ||
297 | state->muted ? "on" : "off", | ||
298 | state->scan_in_progress ? "yes" : "no", | ||
299 | state->volume); | ||
300 | |||
301 | msp_write_dsp(client, 0x0000, val); | ||
302 | msp_write_dsp(client, 0x0007, reallymuted ? 0x1 : (val | 0x1)); | ||
303 | if (state->has_scart2_out_volume) | ||
304 | msp_write_dsp(client, 0x0040, reallymuted ? 0x1 : (val | 0x1)); | ||
305 | if (state->has_headphones) | ||
306 | msp_write_dsp(client, 0x0006, val); | ||
307 | if (!state->has_sound_processing) | ||
308 | return; | ||
309 | |||
310 | if (val) | ||
311 | bal = (u8)((state->balance / 256) - 128); | ||
312 | bass = ((state->bass - 32768) * 0x60 / 65535) << 8; | ||
313 | treble = ((state->treble - 32768) * 0x60 / 65535) << 8; | ||
314 | loudness = state->loudness ? ((5 * 4) << 8) : 0; | ||
315 | |||
316 | v4l_dbg(1, msp_debug, client, "balance=%d bass=%d treble=%d loudness=%d\n", | ||
317 | state->balance, state->bass, state->treble, state->loudness); | ||
318 | |||
319 | msp_write_dsp(client, 0x0001, bal << 8); | ||
320 | msp_write_dsp(client, 0x0002, bass); | ||
321 | msp_write_dsp(client, 0x0003, treble); | ||
322 | msp_write_dsp(client, 0x0004, loudness); | ||
323 | if (!state->has_headphones) | ||
324 | return; | ||
325 | msp_write_dsp(client, 0x0030, bal << 8); | ||
326 | msp_write_dsp(client, 0x0031, bass); | ||
327 | msp_write_dsp(client, 0x0032, treble); | ||
328 | msp_write_dsp(client, 0x0033, loudness); | ||
329 | } | ||
330 | |||
331 | /* ------------------------------------------------------------------------ */ | 286 | /* ------------------------------------------------------------------------ */ |
332 | 287 | ||
333 | static void msp_wake_thread(struct i2c_client *client) | 288 | static void msp_wake_thread(struct i2c_client *client) |
@@ -363,98 +318,73 @@ int msp_sleep(struct msp_state *state, int timeout) | |||
363 | 318 | ||
364 | /* ------------------------------------------------------------------------ */ | 319 | /* ------------------------------------------------------------------------ */ |
365 | 320 | ||
366 | static int msp_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | 321 | static int msp_s_ctrl(struct v4l2_ctrl *ctrl) |
367 | { | 322 | { |
368 | struct msp_state *state = to_state(sd); | 323 | struct msp_state *state = ctrl_to_state(ctrl); |
324 | struct i2c_client *client = v4l2_get_subdevdata(&state->sd); | ||
325 | int val = ctrl->val; | ||
369 | 326 | ||
370 | switch (ctrl->id) { | 327 | switch (ctrl->id) { |
371 | case V4L2_CID_AUDIO_VOLUME: | 328 | case V4L2_CID_AUDIO_VOLUME: { |
372 | ctrl->value = state->volume; | 329 | /* audio volume cluster */ |
373 | break; | 330 | int reallymuted = state->muted->val | state->scan_in_progress; |
374 | 331 | ||
375 | case V4L2_CID_AUDIO_MUTE: | 332 | if (!reallymuted) |
376 | ctrl->value = state->muted; | 333 | val = (val * 0x7f / 65535) << 8; |
377 | break; | 334 | |
378 | 335 | v4l_dbg(1, msp_debug, client, "mute=%s scanning=%s volume=%d\n", | |
379 | case V4L2_CID_AUDIO_BALANCE: | 336 | state->muted->val ? "on" : "off", |
380 | if (!state->has_sound_processing) | 337 | state->scan_in_progress ? "yes" : "no", |
381 | return -EINVAL; | 338 | state->volume->val); |
382 | ctrl->value = state->balance; | 339 | |
383 | break; | 340 | msp_write_dsp(client, 0x0000, val); |
384 | 341 | msp_write_dsp(client, 0x0007, reallymuted ? 0x1 : (val | 0x1)); | |
385 | case V4L2_CID_AUDIO_BASS: | 342 | if (state->has_scart2_out_volume) |
386 | if (!state->has_sound_processing) | 343 | msp_write_dsp(client, 0x0040, reallymuted ? 0x1 : (val | 0x1)); |
387 | return -EINVAL; | 344 | if (state->has_headphones) |
388 | ctrl->value = state->bass; | 345 | msp_write_dsp(client, 0x0006, val); |
389 | break; | 346 | break; |
390 | |||
391 | case V4L2_CID_AUDIO_TREBLE: | ||
392 | if (!state->has_sound_processing) | ||
393 | return -EINVAL; | ||
394 | ctrl->value = state->treble; | ||
395 | break; | ||
396 | |||
397 | case V4L2_CID_AUDIO_LOUDNESS: | ||
398 | if (!state->has_sound_processing) | ||
399 | return -EINVAL; | ||
400 | ctrl->value = state->loudness; | ||
401 | break; | ||
402 | |||
403 | default: | ||
404 | return -EINVAL; | ||
405 | } | 347 | } |
406 | return 0; | ||
407 | } | ||
408 | |||
409 | static int msp_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | ||
410 | { | ||
411 | struct msp_state *state = to_state(sd); | ||
412 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
413 | |||
414 | switch (ctrl->id) { | ||
415 | case V4L2_CID_AUDIO_VOLUME: | ||
416 | state->volume = ctrl->value; | ||
417 | if (state->volume == 0) | ||
418 | state->balance = 32768; | ||
419 | break; | ||
420 | |||
421 | case V4L2_CID_AUDIO_MUTE: | ||
422 | if (ctrl->value < 0 || ctrl->value >= 2) | ||
423 | return -ERANGE; | ||
424 | state->muted = ctrl->value; | ||
425 | break; | ||
426 | 348 | ||
427 | case V4L2_CID_AUDIO_BASS: | 349 | case V4L2_CID_AUDIO_BASS: |
428 | if (!state->has_sound_processing) | 350 | val = ((val - 32768) * 0x60 / 65535) << 8; |
429 | return -EINVAL; | 351 | msp_write_dsp(client, 0x0002, val); |
430 | state->bass = ctrl->value; | 352 | if (state->has_headphones) |
353 | msp_write_dsp(client, 0x0031, val); | ||
431 | break; | 354 | break; |
432 | 355 | ||
433 | case V4L2_CID_AUDIO_TREBLE: | 356 | case V4L2_CID_AUDIO_TREBLE: |
434 | if (!state->has_sound_processing) | 357 | val = ((val - 32768) * 0x60 / 65535) << 8; |
435 | return -EINVAL; | 358 | msp_write_dsp(client, 0x0003, val); |
436 | state->treble = ctrl->value; | 359 | if (state->has_headphones) |
360 | msp_write_dsp(client, 0x0032, val); | ||
437 | break; | 361 | break; |
438 | 362 | ||
439 | case V4L2_CID_AUDIO_LOUDNESS: | 363 | case V4L2_CID_AUDIO_LOUDNESS: |
440 | if (!state->has_sound_processing) | 364 | val = val ? ((5 * 4) << 8) : 0; |
441 | return -EINVAL; | 365 | msp_write_dsp(client, 0x0004, val); |
442 | state->loudness = ctrl->value; | 366 | if (state->has_headphones) |
367 | msp_write_dsp(client, 0x0033, val); | ||
443 | break; | 368 | break; |
444 | 369 | ||
445 | case V4L2_CID_AUDIO_BALANCE: | 370 | case V4L2_CID_AUDIO_BALANCE: |
446 | if (!state->has_sound_processing) | 371 | val = (u8)((val / 256) - 128); |
447 | return -EINVAL; | 372 | msp_write_dsp(client, 0x0001, val << 8); |
448 | state->balance = ctrl->value; | 373 | if (state->has_headphones) |
374 | msp_write_dsp(client, 0x0030, val << 8); | ||
449 | break; | 375 | break; |
450 | 376 | ||
451 | default: | 377 | default: |
452 | return -EINVAL; | 378 | return -EINVAL; |
453 | } | 379 | } |
454 | msp_set_audio(client); | ||
455 | return 0; | 380 | return 0; |
456 | } | 381 | } |
457 | 382 | ||
383 | void msp_update_volume(struct msp_state *state) | ||
384 | { | ||
385 | v4l2_ctrl_s_ctrl(state->volume, v4l2_ctrl_g_ctrl(state->volume)); | ||
386 | } | ||
387 | |||
458 | /* --- v4l2 ioctls --- */ | 388 | /* --- v4l2 ioctls --- */ |
459 | static int msp_s_radio(struct v4l2_subdev *sd) | 389 | static int msp_s_radio(struct v4l2_subdev *sd) |
460 | { | 390 | { |
@@ -472,7 +402,7 @@ static int msp_s_radio(struct v4l2_subdev *sd) | |||
472 | msp3400c_set_mode(client, MSP_MODE_FM_RADIO); | 402 | msp3400c_set_mode(client, MSP_MODE_FM_RADIO); |
473 | msp3400c_set_carrier(client, MSP_CARRIER(10.7), | 403 | msp3400c_set_carrier(client, MSP_CARRIER(10.7), |
474 | MSP_CARRIER(10.7)); | 404 | MSP_CARRIER(10.7)); |
475 | msp_set_audio(client); | 405 | msp_update_volume(state); |
476 | break; | 406 | break; |
477 | case OPMODE_AUTODETECT: | 407 | case OPMODE_AUTODETECT: |
478 | case OPMODE_AUTOSELECT: | 408 | case OPMODE_AUTOSELECT: |
@@ -592,33 +522,6 @@ static int msp_s_i2s_clock_freq(struct v4l2_subdev *sd, u32 freq) | |||
592 | return 0; | 522 | return 0; |
593 | } | 523 | } |
594 | 524 | ||
595 | static int msp_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc) | ||
596 | { | ||
597 | struct msp_state *state = to_state(sd); | ||
598 | |||
599 | switch (qc->id) { | ||
600 | case V4L2_CID_AUDIO_VOLUME: | ||
601 | return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 58880); | ||
602 | case V4L2_CID_AUDIO_MUTE: | ||
603 | return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0); | ||
604 | default: | ||
605 | break; | ||
606 | } | ||
607 | if (!state->has_sound_processing) | ||
608 | return -EINVAL; | ||
609 | switch (qc->id) { | ||
610 | case V4L2_CID_AUDIO_LOUDNESS: | ||
611 | return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0); | ||
612 | case V4L2_CID_AUDIO_BALANCE: | ||
613 | case V4L2_CID_AUDIO_BASS: | ||
614 | case V4L2_CID_AUDIO_TREBLE: | ||
615 | return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 32768); | ||
616 | default: | ||
617 | return -EINVAL; | ||
618 | } | ||
619 | return 0; | ||
620 | } | ||
621 | |||
622 | static int msp_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip) | 525 | static int msp_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip) |
623 | { | 526 | { |
624 | struct msp_state *state = to_state(sd); | 527 | struct msp_state *state = to_state(sd); |
@@ -633,19 +536,14 @@ static int msp_log_status(struct v4l2_subdev *sd) | |||
633 | struct msp_state *state = to_state(sd); | 536 | struct msp_state *state = to_state(sd); |
634 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 537 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
635 | const char *p; | 538 | const char *p; |
539 | char prefix[V4L2_SUBDEV_NAME_SIZE + 20]; | ||
636 | 540 | ||
637 | if (state->opmode == OPMODE_AUTOSELECT) | 541 | if (state->opmode == OPMODE_AUTOSELECT) |
638 | msp_detect_stereo(client); | 542 | msp_detect_stereo(client); |
639 | v4l_info(client, "%s rev1 = 0x%04x rev2 = 0x%04x\n", | 543 | v4l_info(client, "%s rev1 = 0x%04x rev2 = 0x%04x\n", |
640 | client->name, state->rev1, state->rev2); | 544 | client->name, state->rev1, state->rev2); |
641 | v4l_info(client, "Audio: volume %d%s\n", | 545 | snprintf(prefix, sizeof(prefix), "%s: Audio: ", sd->name); |
642 | state->volume, state->muted ? " (muted)" : ""); | 546 | v4l2_ctrl_handler_log_status(&state->hdl, prefix); |
643 | if (state->has_sound_processing) { | ||
644 | v4l_info(client, "Audio: balance %d bass %d treble %d loudness %s\n", | ||
645 | state->balance, state->bass, | ||
646 | state->treble, | ||
647 | state->loudness ? "on" : "off"); | ||
648 | } | ||
649 | switch (state->mode) { | 547 | switch (state->mode) { |
650 | case MSP_MODE_AM_DETECT: p = "AM (for carrier detect)"; break; | 548 | case MSP_MODE_AM_DETECT: p = "AM (for carrier detect)"; break; |
651 | case MSP_MODE_FM_RADIO: p = "FM Radio"; break; | 549 | case MSP_MODE_FM_RADIO: p = "FM Radio"; break; |
@@ -695,12 +593,20 @@ static int msp_resume(struct i2c_client *client) | |||
695 | 593 | ||
696 | /* ----------------------------------------------------------------------- */ | 594 | /* ----------------------------------------------------------------------- */ |
697 | 595 | ||
596 | static const struct v4l2_ctrl_ops msp_ctrl_ops = { | ||
597 | .s_ctrl = msp_s_ctrl, | ||
598 | }; | ||
599 | |||
698 | static const struct v4l2_subdev_core_ops msp_core_ops = { | 600 | static const struct v4l2_subdev_core_ops msp_core_ops = { |
699 | .log_status = msp_log_status, | 601 | .log_status = msp_log_status, |
700 | .g_chip_ident = msp_g_chip_ident, | 602 | .g_chip_ident = msp_g_chip_ident, |
701 | .g_ctrl = msp_g_ctrl, | 603 | .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, |
702 | .s_ctrl = msp_s_ctrl, | 604 | .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, |
703 | .queryctrl = msp_queryctrl, | 605 | .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, |
606 | .g_ctrl = v4l2_subdev_g_ctrl, | ||
607 | .s_ctrl = v4l2_subdev_s_ctrl, | ||
608 | .queryctrl = v4l2_subdev_queryctrl, | ||
609 | .querymenu = v4l2_subdev_querymenu, | ||
704 | .s_std = msp_s_std, | 610 | .s_std = msp_s_std, |
705 | }; | 611 | }; |
706 | 612 | ||
@@ -728,6 +634,7 @@ static int msp_probe(struct i2c_client *client, const struct i2c_device_id *id) | |||
728 | { | 634 | { |
729 | struct msp_state *state; | 635 | struct msp_state *state; |
730 | struct v4l2_subdev *sd; | 636 | struct v4l2_subdev *sd; |
637 | struct v4l2_ctrl_handler *hdl; | ||
731 | int (*thread_func)(void *data) = NULL; | 638 | int (*thread_func)(void *data) = NULL; |
732 | int msp_hard; | 639 | int msp_hard; |
733 | int msp_family; | 640 | int msp_family; |
@@ -752,13 +659,7 @@ static int msp_probe(struct i2c_client *client, const struct i2c_device_id *id) | |||
752 | 659 | ||
753 | state->v4l2_std = V4L2_STD_NTSC; | 660 | state->v4l2_std = V4L2_STD_NTSC; |
754 | state->audmode = V4L2_TUNER_MODE_STEREO; | 661 | state->audmode = V4L2_TUNER_MODE_STEREO; |
755 | state->volume = 58880; /* 0db gain */ | ||
756 | state->balance = 32768; /* 0db gain */ | ||
757 | state->bass = 32768; | ||
758 | state->treble = 32768; | ||
759 | state->loudness = 0; | ||
760 | state->input = -1; | 662 | state->input = -1; |
761 | state->muted = 0; | ||
762 | state->i2s_mode = 0; | 663 | state->i2s_mode = 0; |
763 | init_waitqueue_head(&state->wq); | 664 | init_waitqueue_head(&state->wq); |
764 | /* These are the reset input/output positions */ | 665 | /* These are the reset input/output positions */ |
@@ -777,8 +678,6 @@ static int msp_probe(struct i2c_client *client, const struct i2c_device_id *id) | |||
777 | return -ENODEV; | 678 | return -ENODEV; |
778 | } | 679 | } |
779 | 680 | ||
780 | msp_set_audio(client); | ||
781 | |||
782 | msp_family = ((state->rev1 >> 4) & 0x0f) + 3; | 681 | msp_family = ((state->rev1 >> 4) & 0x0f) + 3; |
783 | msp_product = (state->rev2 >> 8) & 0xff; | 682 | msp_product = (state->rev2 >> 8) & 0xff; |
784 | msp_prod_hi = msp_product / 10; | 683 | msp_prod_hi = msp_product / 10; |
@@ -849,6 +748,34 @@ static int msp_probe(struct i2c_client *client, const struct i2c_device_id *id) | |||
849 | state->opmode = OPMODE_MANUAL; | 748 | state->opmode = OPMODE_MANUAL; |
850 | } | 749 | } |
851 | 750 | ||
751 | hdl = &state->hdl; | ||
752 | v4l2_ctrl_handler_init(hdl, 6); | ||
753 | if (state->has_sound_processing) { | ||
754 | v4l2_ctrl_new_std(hdl, &msp_ctrl_ops, | ||
755 | V4L2_CID_AUDIO_BASS, 0, 65535, 65535 / 100, 32768); | ||
756 | v4l2_ctrl_new_std(hdl, &msp_ctrl_ops, | ||
757 | V4L2_CID_AUDIO_TREBLE, 0, 65535, 65535 / 100, 32768); | ||
758 | v4l2_ctrl_new_std(hdl, &msp_ctrl_ops, | ||
759 | V4L2_CID_AUDIO_LOUDNESS, 0, 1, 1, 0); | ||
760 | } | ||
761 | state->volume = v4l2_ctrl_new_std(hdl, &msp_ctrl_ops, | ||
762 | V4L2_CID_AUDIO_VOLUME, 0, 65535, 65535 / 100, 58880); | ||
763 | v4l2_ctrl_new_std(hdl, &msp_ctrl_ops, | ||
764 | V4L2_CID_AUDIO_BALANCE, 0, 65535, 65535 / 100, 32768); | ||
765 | state->muted = v4l2_ctrl_new_std(hdl, &msp_ctrl_ops, | ||
766 | V4L2_CID_AUDIO_MUTE, 0, 1, 1, 0); | ||
767 | sd->ctrl_handler = hdl; | ||
768 | if (hdl->error) { | ||
769 | int err = hdl->error; | ||
770 | |||
771 | v4l2_ctrl_handler_free(hdl); | ||
772 | kfree(state); | ||
773 | return err; | ||
774 | } | ||
775 | |||
776 | v4l2_ctrl_cluster(2, &state->volume); | ||
777 | v4l2_ctrl_handler_setup(hdl); | ||
778 | |||
852 | /* hello world :-) */ | 779 | /* hello world :-) */ |
853 | v4l_info(client, "MSP%d4%02d%c-%c%d found @ 0x%x (%s)\n", | 780 | v4l_info(client, "MSP%d4%02d%c-%c%d found @ 0x%x (%s)\n", |
854 | msp_family, msp_product, | 781 | msp_family, msp_product, |
@@ -903,6 +830,7 @@ static int msp_remove(struct i2c_client *client) | |||
903 | } | 830 | } |
904 | msp_reset(client); | 831 | msp_reset(client); |
905 | 832 | ||
833 | v4l2_ctrl_handler_free(&state->hdl); | ||
906 | kfree(state); | 834 | kfree(state); |
907 | return 0; | 835 | return 0; |
908 | } | 836 | } |