V4L/DVB: cx25840, v4l2-subdev, ivtv, pvrusb2: Fix ivtv/cx25840 tinny audio
authorAndy Walls <awalls@radix.net>
Thu, 24 Dec 2009 16:06:08 +0000 (13:06 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Fri, 26 Feb 2010 18:10:41 +0000 (15:10 -0300)
This change attempts to fix the ivtv tinny audio problem by keeping digitizer
to encoder audio clocks running, while disabling the video clocks as needed to
avoid unpredictable PCI bus hangs.

To accomplish this, for the cx25840 module enabling of audio streaming had
to be separated from enabling video streaming, requiring an additional
v4l2_subdev_audio_op and calls to this new op in the pvrusb2 and ivtv drivers.

The cx231xx and cx23885 driver use the cx25840 module for affecting only
video on s_stream calls, so those drivers needed no change.

The CX23418 hardware does not exhibit either the tinny audio problem nor the PCI
bus hang, so the cx18 driver did not need corresponding changes.

CX2341[56] based cards that are not using the CX2584x family of chips
do not seem to be affected by the tinny audio problem, and this change should
not affect how they are configured. It will delay their first capture by
starting by another 300 msec though.

Many thanks go to Argus <pthorn-ivtvd@styx2002.no-ip.org> and
Martin Dauskardt <martin.dauskardt@gmx.de> whose persistent testing and
investigation of this problem will hopefully fix this problem once and for all
for many ivtv users.

Reported-by: Martin Dauskardt <martin.dauskardt@gmx.de>
Reported-by: Argus <pthorn-ivtvd@styx2002.no-ip.org>
Signed-off-by: Andy Walls <awalls@radix.net>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
drivers/media/video/cx25840/cx25840-core.c
drivers/media/video/ivtv/ivtv-streams.c
drivers/media/video/pvrusb2/pvrusb2-hdw.c
include/media/v4l2-subdev.h

index 385ecd58f1c06a70820fe35df0c5ed92d31f9caf..796f12d59daa4bfba90b862bb80ad34bdcbd88d7 100644 (file)
@@ -1347,30 +1347,59 @@ static int cx25840_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *
 }
 #endif
 
+static int cx25840_s_audio_stream(struct v4l2_subdev *sd, int enable)
+{
+       struct cx25840_state *state = to_state(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       u8 v;
+
+       if (is_cx2583x(state) || is_cx2388x(state) || is_cx231xx(state))
+               return 0;
+
+       v4l_dbg(1, cx25840_debug, client, "%s audio output\n",
+                       enable ? "enable" : "disable");
+
+       if (enable) {
+               v = cx25840_read(client, 0x115) | 0x80;
+               cx25840_write(client, 0x115, v);
+               v = cx25840_read(client, 0x116) | 0x03;
+               cx25840_write(client, 0x116, v);
+       } else {
+               v = cx25840_read(client, 0x115) & ~(0x80);
+               cx25840_write(client, 0x115, v);
+               v = cx25840_read(client, 0x116) & ~(0x03);
+               cx25840_write(client, 0x116, v);
+       }
+       return 0;
+}
+
 static int cx25840_s_stream(struct v4l2_subdev *sd, int enable)
 {
        struct cx25840_state *state = to_state(sd);
        struct i2c_client *client = v4l2_get_subdevdata(sd);
+       u8 v;
 
-       v4l_dbg(1, cx25840_debug, client, "%s output\n",
+       v4l_dbg(1, cx25840_debug, client, "%s video output\n",
                        enable ? "enable" : "disable");
        if (enable) {
                if (is_cx2388x(state) || is_cx231xx(state)) {
-                       u8 v = (cx25840_read(client, 0x421) | 0x0b);
+                       v = cx25840_read(client, 0x421) | 0x0b;
                        cx25840_write(client, 0x421, v);
                } else {
-                       cx25840_write(client, 0x115,
-                                       is_cx2583x(state) ? 0x0c : 0x8c);
-                       cx25840_write(client, 0x116,
-                                       is_cx2583x(state) ? 0x04 : 0x07);
+                       v = cx25840_read(client, 0x115) | 0x0c;
+                       cx25840_write(client, 0x115, v);
+                       v = cx25840_read(client, 0x116) | 0x04;
+                       cx25840_write(client, 0x116, v);
                }
        } else {
                if (is_cx2388x(state) || is_cx231xx(state)) {
-                       u8 v = cx25840_read(client, 0x421) & ~(0x0b);
+                       v = cx25840_read(client, 0x421) & ~(0x0b);
                        cx25840_write(client, 0x421, v);
                } else {
-                       cx25840_write(client, 0x115, 0x00);
-                       cx25840_write(client, 0x116, 0x00);
+                       v = cx25840_read(client, 0x115) & ~(0x0c);
+                       cx25840_write(client, 0x115, v);
+                       v = cx25840_read(client, 0x116) & ~(0x04);
+                       cx25840_write(client, 0x116, v);
                }
        }
        return 0;
@@ -1601,6 +1630,7 @@ static const struct v4l2_subdev_tuner_ops cx25840_tuner_ops = {
 static const struct v4l2_subdev_audio_ops cx25840_audio_ops = {
        .s_clock_freq = cx25840_s_clock_freq,
        .s_routing = cx25840_s_audio_routing,
+       .s_stream = cx25840_s_audio_stream,
 };
 
 static const struct v4l2_subdev_video_ops cx25840_video_ops = {
index e12c6022373e38afaaf0ad3b559f3184b67456f9..2f90dd255cd7be75886a05d67e9b80bf6238c04d 100644 (file)
@@ -577,10 +577,14 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s)
                clear_bit(IVTV_F_I_EOS, &itv->i_flags);
 
                /* Initialize Digitizer for Capture */
+               /* Avoid tinny audio problem - ensure audio clocks are going */
+               v4l2_subdev_call(itv->sd_audio, audio, s_stream, 1);
+               /* Avoid unpredictable PCI bus hang - disable video clocks */
                v4l2_subdev_call(itv->sd_video, video, s_stream, 0);
                ivtv_msleep_timeout(300, 1);
                ivtv_vapi(itv, CX2341X_ENC_INITIALIZE_INPUT, 0);
                v4l2_subdev_call(itv->sd_video, video, s_stream, 1);
+               ivtv_msleep_timeout(300, 1);
        }
 
        /* begin_capture */
index 1bbdab08fe0e67ee765a0dd847b3837fc4e8b0ef..ad9ed51f7b9d31da54ce0d7dc2e91f7c2d5cc6d9 100644 (file)
@@ -1705,6 +1705,7 @@ static int pvr2_decoder_enable(struct pvr2_hdw *hdw,int enablefl)
        pvr2_trace(PVR2_TRACE_CHIPS, "subdev v4l2 stream=%s",
                   (enablefl ? "on" : "off"));
        v4l2_device_call_all(&hdw->v4l2_dev, 0, video, s_stream, enablefl);
+       v4l2_device_call_all(&hdw->v4l2_dev, 0, audio, s_stream, enablefl);
        if (hdw->decoder_client_id) {
                /* We get here if the encoder has been noticed.  Otherwise
                   we'll issue a warning to the user (which should
index 9ba99cd39ee7815c121e2be2f06f787bb1bffc30..2bcdca0a57fc6f5a5b4f4b0231bdc298fee3787f 100644 (file)
@@ -180,6 +180,7 @@ struct v4l2_subdev_audio_ops {
        int (*s_clock_freq)(struct v4l2_subdev *sd, u32 freq);
        int (*s_i2s_clock_freq)(struct v4l2_subdev *sd, u32 freq);
        int (*s_routing)(struct v4l2_subdev *sd, u32 input, u32 output, u32 config);
+       int (*s_stream)(struct v4l2_subdev *sd, int enable);
 };
 
 /*