linux 2.6.16.38 w/ vs2.0.3-rc1
[linux-2.6.git] / drivers / media / video / cx25840 / cx25840-core.c
index a961bb2..5588b9a 100644 (file)
 #include <linux/slab.h>
 #include <linux/videodev2.h>
 #include <linux/i2c.h>
+#include <media/audiochip.h>
 #include <media/v4l2-common.h>
-#include <media/cx25840.h>
 
-#include "cx25840-core.h"
+#include "cx25840.h"
 
 MODULE_DESCRIPTION("Conexant CX25840 audio/video decoder driver");
 MODULE_AUTHOR("Ulf Eklund, Chris Kennedy, Hans Verkuil, Tyler Trafford");
@@ -176,9 +176,9 @@ static void cx25840_initialize(struct i2c_client *client, int loadfw)
        cx25840_write(client, 0x4a5, 0x00);
        cx25840_write(client, 0x402, 0x00);
        /* 8. */
-       cx25840_and_or(client, 0x401, ~0x18, 0);
-       cx25840_and_or(client, 0x4a2, ~0x10, 0x10);
-       /* steps 8c and 8d are done in change_input() */
+       cx25840_write(client, 0x401, 0x18);
+       cx25840_write(client, 0x4a2, 0x10);
+       cx25840_write(client, 0x402, 0x04);
        /* 10. */
        cx25840_write(client, 0x8d3, 0x1f);
        cx25840_write(client, 0x8e3, 0x03);
@@ -209,17 +209,6 @@ static void input_change(struct i2c_client *client)
        struct cx25840_state *state = i2c_get_clientdata(client);
        v4l2_std_id std = cx25840_get_v4lstd(client);
 
-       /* Follow step 8c and 8d of section 3.16 in the cx25840 datasheet */
-       if (std & V4L2_STD_SECAM) {
-               cx25840_write(client, 0x402, 0);
-       }
-       else {
-               cx25840_write(client, 0x402, 0x04);
-               cx25840_write(client, 0x49f, (std & V4L2_STD_NTSC) ? 0x14 : 0x11);
-       }
-       cx25840_and_or(client, 0x401, ~0x60, 0);
-       cx25840_and_or(client, 0x401, ~0x60, 0x60);
-
        /* Note: perhaps V4L2_STD_PAL_M should be handled as V4L2_STD_NTSC
           instead of V4L2_STD_PAL. Someone needs to test this. */
        if (std & V4L2_STD_PAL) {
@@ -354,15 +343,6 @@ static int set_v4lstd(struct i2c_client *client, v4l2_std_id std)
                }
        }
 
-       /* Follow step 9 of section 3.16 in the cx25840 datasheet.
-          Without this PAL may display a vertical ghosting effect.
-          This happens for example with the Yuan MPC622. */
-       if (fmt >= 4 && fmt < 8) {
-               /* Set format to NTSC-M */
-               cx25840_and_or(client, 0x400, ~0xf, 1);
-               /* Turn off LCOMB */
-               cx25840_and_or(client, 0x47b, ~6, 0);
-       }
        cx25840_and_or(client, 0x400, ~0xf, fmt);
        cx25840_vbi_setup(client);
        return 0;
@@ -379,14 +359,7 @@ v4l2_std_id cx25840_get_v4lstd(struct i2c_client * client)
        }
 
        switch (fmt) {
-       case 0x1:
-       {
-               /* if the audio std is A2-M, then this is the South Korean
-                  NTSC standard */
-               if (cx25840_read(client, 0x805) == 2)
-                       return V4L2_STD_NTSC_M_KR;
-               return V4L2_STD_NTSC_M;
-       }
+       case 0x1: return V4L2_STD_NTSC_M | V4L2_STD_NTSC_M_KR;
        case 0x2: return V4L2_STD_NTSC_M_JP;
        case 0x3: return V4L2_STD_NTSC_443;
        case 0x4: return V4L2_STD_PAL;
@@ -669,7 +642,6 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
 {
        struct cx25840_state *state = i2c_get_clientdata(client);
        struct v4l2_tuner *vt = arg;
-       struct v4l2_routing *route = arg;
 
        switch (cmd) {
 #ifdef CONFIG_VIDEO_ADV_DEBUG
@@ -751,21 +723,28 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
                state->radio = 1;
                break;
 
-       case VIDIOC_INT_G_VIDEO_ROUTING:
-               route->input = state->vid_input;
-               route->output = 0;
+       case VIDIOC_G_INPUT:
+               *(int *)arg = state->vid_input;
                break;
 
-       case VIDIOC_INT_S_VIDEO_ROUTING:
-               return set_input(client, route->input, state->aud_input);
+       case VIDIOC_S_INPUT:
+               return set_input(client, *(enum cx25840_video_input *)arg, state->aud_input);
 
-       case VIDIOC_INT_G_AUDIO_ROUTING:
-               route->input = state->aud_input;
-               route->output = 0;
-               break;
+       case VIDIOC_S_AUDIO:
+       {
+               struct v4l2_audio *input = arg;
+
+               return set_input(client, state->vid_input, input->index);
+       }
 
-       case VIDIOC_INT_S_AUDIO_ROUTING:
-               return set_input(client, state->vid_input, route->input);
+       case VIDIOC_G_AUDIO:
+       {
+               struct v4l2_audio *input = arg;
+
+               memset(input, 0, sizeof(*input));
+               input->index = state->aud_input;
+               break;
+       }
 
        case VIDIOC_S_FREQUENCY:
                input_change(client);
@@ -774,6 +753,7 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
        case VIDIOC_G_TUNER:
        {
                u8 mode = cx25840_read(client, 0x804);
+               u8 pref = cx25840_read(client, 0x809) & 0xf;
                u8 vpres = cx25840_read(client, 0x80a) & 0x10;
                int val = 0;
 
@@ -793,50 +773,44 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
                        val |= V4L2_TUNER_SUB_MONO;
 
                if (mode == 2 || mode == 4)
-                       val = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
+                       val |= V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
 
                if (mode & 0x10)
                        val |= V4L2_TUNER_SUB_SAP;
 
                vt->rxsubchans = val;
-               vt->audmode = state->audmode;
+
+               switch (pref) {
+               case 0:
+                       vt->audmode = V4L2_TUNER_MODE_MONO;
+                       break;
+               case 1:
+               case 2:
+                       vt->audmode = V4L2_TUNER_MODE_LANG2;
+                       break;
+               case 4:
+               default:
+                       vt->audmode = V4L2_TUNER_MODE_STEREO;
+               }
                break;
        }
 
        case VIDIOC_S_TUNER:
-               if (state->radio)
-                       break;
-
                switch (vt->audmode) {
                case V4L2_TUNER_MODE_MONO:
-                       /* mono      -> mono
-                          stereo    -> mono
-                          bilingual -> lang1 */
+               case V4L2_TUNER_MODE_LANG1:
+                       /* Force PREF_MODE to MONO */
                        cx25840_and_or(client, 0x809, ~0xf, 0x00);
                        break;
                case V4L2_TUNER_MODE_STEREO:
-               case V4L2_TUNER_MODE_LANG1:
-                       /* mono      -> mono
-                          stereo    -> stereo
-                          bilingual -> lang1 */
+                       /* Force PREF_MODE to STEREO */
                        cx25840_and_or(client, 0x809, ~0xf, 0x04);
                        break;
-               case V4L2_TUNER_MODE_LANG1_LANG2:
-                       /* mono      -> mono
-                          stereo    -> stereo
-                          bilingual -> lang1/lang2 */
-                       cx25840_and_or(client, 0x809, ~0xf, 0x07);
-                       break;
                case V4L2_TUNER_MODE_LANG2:
-                       /* mono      -> mono
-                          stereo    -> stereo
-                          bilingual -> lang2 */
+                       /* Force PREF_MODE to LANG2 */
                        cx25840_and_or(client, 0x809, ~0xf, 0x01);
                        break;
-               default:
-                       return -EINVAL;
                }
-               state->audmode = vt->audmode;
                break;
 
        case VIDIOC_G_FMT:
@@ -917,7 +891,6 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address,
        state->aud_input = CX25840_AUDIO8;
        state->audclk_freq = 48000;
        state->pvr150_workaround = 0;
-       state->audmode = V4L2_TUNER_MODE_LANG1;
 
        cx25840_initialize(client, 1);