]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/media/video/cx25840/cx25840-audio.c
Merge branch 'sched-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[linux-2.6-omap-h63xx.git] / drivers / media / video / cx25840 / cx25840-audio.c
index f897c1ebd5f3d809f4bf6bf6f111b2754395a4bc..d6421e1e8f6a793e0cdaeddca6885e9746b188e3 100644 (file)
@@ -32,118 +32,156 @@ static int set_audclk_freq(struct i2c_client *client, u32 freq)
 
        /* common for all inputs and rates */
        /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x10 */
-       cx25840_write(client, 0x127, 0x50);
+       if (!state->is_cx23885)
+               cx25840_write(client, 0x127, 0x50);
 
        if (state->aud_input != CX25840_AUDIO_SERIAL) {
                switch (freq) {
                case 32000:
+                       if (state->is_cx23885) {
+                               /* We don't have register values
+                                * so avoid destroying registers. */
+                               break;
+                       }
                        /* VID_PLL and AUX_PLL */
-                       cx25840_write4(client, 0x108, 0x0f040610);
+                       cx25840_write4(client, 0x108, 0x1006040f);
 
                        /* AUX_PLL_FRAC */
-                       cx25840_write4(client, 0x110, 0xee39bb01);
+                       cx25840_write4(client, 0x110, 0x01bb39ee);
 
                        if (state->is_cx25836)
                                break;
 
                        /* src3/4/6_ctl = 0x0801f77f */
-                       cx25840_write4(client, 0x900, 0x7ff70108);
-                       cx25840_write4(client, 0x904, 0x7ff70108);
-                       cx25840_write4(client, 0x90c, 0x7ff70108);
+                       cx25840_write4(client, 0x900, 0x0801f77f);
+                       cx25840_write4(client, 0x904, 0x0801f77f);
+                       cx25840_write4(client, 0x90c, 0x0801f77f);
                        break;
 
                case 44100:
+                       if (state->is_cx23885) {
+                               /* We don't have register values
+                                * so avoid destroying registers. */
+                               break;
+                       }
                        /* VID_PLL and AUX_PLL */
-                       cx25840_write4(client, 0x108, 0x0f040910);
+                       cx25840_write4(client, 0x108, 0x1009040f);
 
                        /* AUX_PLL_FRAC */
-                       cx25840_write4(client, 0x110, 0xd66bec00);
+                       cx25840_write4(client, 0x110, 0x00ec6bd6);
 
                        if (state->is_cx25836)
                                break;
 
                        /* src3/4/6_ctl = 0x08016d59 */
-                       cx25840_write4(client, 0x900, 0x596d0108);
-                       cx25840_write4(client, 0x904, 0x596d0108);
-                       cx25840_write4(client, 0x90c, 0x596d0108);
+                       cx25840_write4(client, 0x900, 0x08016d59);
+                       cx25840_write4(client, 0x904, 0x08016d59);
+                       cx25840_write4(client, 0x90c, 0x08016d59);
                        break;
 
                case 48000:
+                       if (state->is_cx23885) {
+                               /* We don't have register values
+                                * so avoid destroying registers. */
+                               break;
+                       }
                        /* VID_PLL and AUX_PLL */
-                       cx25840_write4(client, 0x108, 0x0f040a10);
+                       cx25840_write4(client, 0x108, 0x100a040f);
 
                        /* AUX_PLL_FRAC */
-                       cx25840_write4(client, 0x110, 0xe5d69800);
+                       cx25840_write4(client, 0x110, 0x0098d6e5);
 
                        if (state->is_cx25836)
                                break;
 
                        /* src3/4/6_ctl = 0x08014faa */
-                       cx25840_write4(client, 0x900, 0xaa4f0108);
-                       cx25840_write4(client, 0x904, 0xaa4f0108);
-                       cx25840_write4(client, 0x90c, 0xaa4f0108);
+                       cx25840_write4(client, 0x900, 0x08014faa);
+                       cx25840_write4(client, 0x904, 0x08014faa);
+                       cx25840_write4(client, 0x90c, 0x08014faa);
                        break;
                }
        } else {
                switch (freq) {
                case 32000:
+                       if (state->is_cx23885) {
+                               /* We don't have register values
+                                * so avoid destroying registers. */
+                               break;
+                       }
                        /* VID_PLL and AUX_PLL */
-                       cx25840_write4(client, 0x108, 0x0f04081e);
+                       cx25840_write4(client, 0x108, 0x1e08040f);
 
                        /* AUX_PLL_FRAC */
-                       cx25840_write4(client, 0x110, 0x69082a01);
+                       cx25840_write4(client, 0x110, 0x012a0869);
 
                        if (state->is_cx25836)
                                break;
 
                        /* src1_ctl = 0x08010000 */
-                       cx25840_write4(client, 0x8f8, 0x00000108);
+                       cx25840_write4(client, 0x8f8, 0x08010000);
 
                        /* src3/4/6_ctl = 0x08020000 */
-                       cx25840_write4(client, 0x900, 0x00000208);
-                       cx25840_write4(client, 0x904, 0x00000208);
-                       cx25840_write4(client, 0x90c, 0x00000208);
+                       cx25840_write4(client, 0x900, 0x08020000);
+                       cx25840_write4(client, 0x904, 0x08020000);
+                       cx25840_write4(client, 0x90c, 0x08020000);
 
                        /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x14 */
                        cx25840_write(client, 0x127, 0x54);
                        break;
 
                case 44100:
+                       if (state->is_cx23885) {
+                               /* We don't have register values
+                                * so avoid destroying registers. */
+                               break;
+                       }
+
                        /* VID_PLL and AUX_PLL */
-                       cx25840_write4(client, 0x108, 0x0f040918);
+                       cx25840_write4(client, 0x108, 0x1809040f);
 
                        /* AUX_PLL_FRAC */
-                       cx25840_write4(client, 0x110, 0xd66bec00);
+                       cx25840_write4(client, 0x110, 0x00ec6bd6);
 
                        if (state->is_cx25836)
                                break;
 
                        /* src1_ctl = 0x08010000 */
-                       cx25840_write4(client, 0x8f8, 0xcd600108);
+                       cx25840_write4(client, 0x8f8, 0x080160cd);
 
                        /* src3/4/6_ctl = 0x08020000 */
-                       cx25840_write4(client, 0x900, 0x85730108);
-                       cx25840_write4(client, 0x904, 0x85730108);
-                       cx25840_write4(client, 0x90c, 0x85730108);
+                       cx25840_write4(client, 0x900, 0x08017385);
+                       cx25840_write4(client, 0x904, 0x08017385);
+                       cx25840_write4(client, 0x90c, 0x08017385);
                        break;
 
                case 48000:
-                       /* VID_PLL and AUX_PLL */
-                       cx25840_write4(client, 0x108, 0x0f040a18);
+                       if (!state->is_cx23885) {
+                               /* VID_PLL and AUX_PLL */
+                               cx25840_write4(client, 0x108, 0x180a040f);
 
-                       /* AUX_PLL_FRAC */
-                       cx25840_write4(client, 0x110, 0xe5d69800);
+                               /* AUX_PLL_FRAC */
+                               cx25840_write4(client, 0x110, 0x0098d6e5);
+                       }
 
                        if (state->is_cx25836)
                                break;
 
-                       /* src1_ctl = 0x08010000 */
-                       cx25840_write4(client, 0x8f8, 0x00800108);
+                       if (!state->is_cx23885) {
+                               /* src1_ctl */
+                               cx25840_write4(client, 0x8f8, 0x08018000);
 
-                       /* src3/4/6_ctl = 0x08020000 */
-                       cx25840_write4(client, 0x900, 0x55550108);
-                       cx25840_write4(client, 0x904, 0x55550108);
-                       cx25840_write4(client, 0x90c, 0x55550108);
+                               /* src3/4/6_ctl */
+                               cx25840_write4(client, 0x900, 0x08015555);
+                               cx25840_write4(client, 0x904, 0x08015555);
+                               cx25840_write4(client, 0x90c, 0x08015555);
+                       } else {
+
+                               cx25840_write4(client, 0x8f8, 0x0801867c);
+
+                               cx25840_write4(client, 0x900, 0x08014faa);
+                               cx25840_write4(client, 0x904, 0x08014faa);
+                               cx25840_write4(client, 0x90c, 0x08014faa);
+                       }
                        break;
                }
        }
@@ -157,56 +195,74 @@ void cx25840_audio_set_path(struct i2c_client *client)
 {
        struct cx25840_state *state = i2c_get_clientdata(client);
 
+       /* assert soft reset */
+       cx25840_and_or(client, 0x810, ~0x1, 0x01);
+
        /* stop microcontroller */
        cx25840_and_or(client, 0x803, ~0x10, 0);
 
-       /* assert soft reset */
-       if (!state->is_cx25836)
-               cx25840_and_or(client, 0x810, ~0x1, 0x01);
-
        /* Mute everything to prevent the PFFT! */
        cx25840_write(client, 0x8d3, 0x1f);
 
        if (state->aud_input == CX25840_AUDIO_SERIAL) {
                /* Set Path1 to Serial Audio Input */
-               cx25840_write4(client, 0x8d0, 0x12100101);
+               cx25840_write4(client, 0x8d0, 0x01011012);
 
                /* The microcontroller should not be started for the
                 * non-tuner inputs: autodetection is specific for
                 * TV audio. */
        } else {
                /* Set Path1 to Analog Demod Main Channel */
-               cx25840_write4(client, 0x8d0, 0x7038061f);
+               cx25840_write4(client, 0x8d0, 0x1f063870);
        }
 
        set_audclk_freq(client, state->audclk_freq);
 
-       /* deassert soft reset */
-       if (!state->is_cx25836)
-               cx25840_and_or(client, 0x810, ~0x1, 0x00);
-
        if (state->aud_input != CX25840_AUDIO_SERIAL) {
                /* When the microcontroller detects the
                 * audio format, it will unmute the lines */
                cx25840_and_or(client, 0x803, ~0x10, 0x10);
        }
+
+       /* deassert soft reset */
+       cx25840_and_or(client, 0x810, ~0x1, 0x00);
+
+       if (state->is_cx23885) {
+               /* Ensure the controller is running when we exit */
+               cx25840_and_or(client, 0x803, ~0x10, 0x10);
+       }
 }
 
 static int get_volume(struct i2c_client *client)
 {
+       struct cx25840_state *state = i2c_get_clientdata(client);
+       int vol;
+
+       if (state->unmute_volume >= 0)
+               return state->unmute_volume;
+
        /* Volume runs +18dB to -96dB in 1/2dB steps
         * change to fit the msp3400 -114dB to +12dB range */
 
        /* check PATH1_VOLUME */
-       int vol = 228 - cx25840_read(client, 0x8d4);
+       vol = 228 - cx25840_read(client, 0x8d4);
        vol = (vol / 2) + 23;
        return vol << 9;
 }
 
 static void set_volume(struct i2c_client *client, int volume)
 {
-       /* First convert the volume to msp3400 values (0-127) */
-       int vol = volume >> 9;
+       struct cx25840_state *state = i2c_get_clientdata(client);
+       int vol;
+
+       if (state->unmute_volume >= 0) {
+               state->unmute_volume = volume;
+               return;
+       }
+
+       /* Convert the volume to msp3400 values (0-127) */
+       vol = volume >> 9;
+
        /* now scale it up to cx25840 values
         * -114dB to -96dB maps to 0
         * this should be 19, but in my testing that was 4dB too loud */
@@ -284,30 +340,26 @@ static void set_balance(struct i2c_client *client, int balance)
 
 static int get_mute(struct i2c_client *client)
 {
-       /* check SRC1_MUTE_EN */
-       return cx25840_read(client, 0x8d3) & 0x2 ? 1 : 0;
+       struct cx25840_state *state = i2c_get_clientdata(client);
+
+       return state->unmute_volume >= 0;
 }
 
 static void set_mute(struct i2c_client *client, int mute)
 {
        struct cx25840_state *state = i2c_get_clientdata(client);
 
-       if (state->aud_input != CX25840_AUDIO_SERIAL) {
-               /* Must turn off microcontroller in order to mute sound.
-                * Not sure if this is the best method, but it does work.
-                * If the microcontroller is running, then it will undo any
-                * changes to the mute register. */
-               if (mute) {
-                       /* disable microcontroller */
-                       cx25840_and_or(client, 0x803, ~0x10, 0x00);
-                       cx25840_write(client, 0x8d3, 0x1f);
-               } else {
-                       /* enable microcontroller */
-                       cx25840_and_or(client, 0x803, ~0x10, 0x10);
-               }
-       } else {
-               /* SRC1_MUTE_EN */
-               cx25840_and_or(client, 0x8d3, ~0x2, mute ? 0x02 : 0x00);
+       if (mute && state->unmute_volume == -1) {
+               int vol = get_volume(client);
+
+               set_volume(client, 0);
+               state->unmute_volume = vol;
+       }
+       else if (!mute && state->unmute_volume != -1) {
+               int vol = state->unmute_volume;
+
+               state->unmute_volume = -1;
+               set_volume(client, vol);
        }
 }
 
@@ -319,18 +371,18 @@ int cx25840_audio(struct i2c_client *client, unsigned int cmd, void *arg)
 
        switch (cmd) {
        case VIDIOC_INT_AUDIO_CLOCK_FREQ:
+               if (!state->is_cx25836)
+                       cx25840_and_or(client, 0x810, ~0x1, 1);
                if (state->aud_input != CX25840_AUDIO_SERIAL) {
                        cx25840_and_or(client, 0x803, ~0x10, 0);
                        cx25840_write(client, 0x8d3, 0x1f);
                }
-               if (!state->is_cx25836)
-                       cx25840_and_or(client, 0x810, ~0x1, 1);
                retval = set_audclk_freq(client, *(u32 *)arg);
-               if (!state->is_cx25836)
-                       cx25840_and_or(client, 0x810, ~0x1, 0);
                if (state->aud_input != CX25840_AUDIO_SERIAL) {
                        cx25840_and_or(client, 0x803, ~0x10, 0x10);
                }
+               if (!state->is_cx25836)
+                       cx25840_and_or(client, 0x810, ~0x1, 0);
                return retval;
 
        case VIDIOC_G_CTRL: