]> err.no Git - linux-2.6/commitdiff
V4L/DVB (3214): Calculate the saa7115 AMCLK regs instead of using fixed values
authorHans Verkuil <hverkuil@xs4all.nl>
Mon, 9 Jan 2006 17:25:41 +0000 (15:25 -0200)
committerMauro Carvalho Chehab <mchehab@brturbo.com.br>
Mon, 9 Jan 2006 17:25:41 +0000 (15:25 -0200)
- Calculate the audio master clock registers from the actual
frequencies. This simplifies the code and it also prepares
for adding CGC2 support.
- VIDIOC_INT_AUDIO_CLOCK_FREQ now receives an u32 instead of
an enum. It is more generic and actually easier to implement.

Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab@brturbo.com.br>
drivers/media/video/cx25840/cx25840-audio.c
drivers/media/video/cx25840/cx25840-core.c
drivers/media/video/cx25840/cx25840.h
drivers/media/video/saa7115.c
include/media/v4l2-common.h

index 740908f8027d050ad1810d3f497b1a0ff2f3a253..6c44bd9c1704fcd1624ef62c4f0d89a944319e6b 100644 (file)
 
 #include "cx25840.h"
 
 
 #include "cx25840.h"
 
-inline static int set_audclk_freq(struct i2c_client *client,
-                                enum v4l2_audio_clock_freq freq)
+static int set_audclk_freq(struct i2c_client *client, u32 freq)
 {
        struct cx25840_state *state = i2c_get_clientdata(client);
 
 {
        struct cx25840_state *state = i2c_get_clientdata(client);
 
+       if (freq != 32000 && freq != 44100 && freq != 48000)
+               return -EINVAL;
+
        /* assert soft reset */
        cx25840_and_or(client, 0x810, ~0x1, 0x01);
 
        /* assert soft reset */
        cx25840_and_or(client, 0x810, ~0x1, 0x01);
 
@@ -38,7 +40,7 @@ inline static int set_audclk_freq(struct i2c_client *client,
        switch (state->audio_input) {
        case AUDIO_TUNER:
                switch (freq) {
        switch (state->audio_input) {
        case AUDIO_TUNER:
                switch (freq) {
-               case V4L2_AUDCLK_32_KHZ:
+               case 32000:
                        /* VID_PLL and AUX_PLL */
                        cx25840_write4(client, 0x108, 0x0f040610);
 
                        /* VID_PLL and AUX_PLL */
                        cx25840_write4(client, 0x108, 0x0f040610);
 
@@ -51,7 +53,7 @@ inline static int set_audclk_freq(struct i2c_client *client,
                        cx25840_write4(client, 0x90c, 0x7ff70108);
                        break;
 
                        cx25840_write4(client, 0x90c, 0x7ff70108);
                        break;
 
-               case V4L2_AUDCLK_441_KHZ:
+               case 44100:
                        /* VID_PLL and AUX_PLL */
                        cx25840_write4(client, 0x108, 0x0f040910);
 
                        /* VID_PLL and AUX_PLL */
                        cx25840_write4(client, 0x108, 0x0f040910);
 
@@ -64,7 +66,7 @@ inline static int set_audclk_freq(struct i2c_client *client,
                        cx25840_write4(client, 0x90c, 0x596d0108);
                        break;
 
                        cx25840_write4(client, 0x90c, 0x596d0108);
                        break;
 
-               case V4L2_AUDCLK_48_KHZ:
+               case 48000:
                        /* VID_PLL and AUX_PLL */
                        cx25840_write4(client, 0x108, 0x0f040a10);
 
                        /* VID_PLL and AUX_PLL */
                        cx25840_write4(client, 0x108, 0x0f040a10);
 
@@ -84,7 +86,7 @@ inline static int set_audclk_freq(struct i2c_client *client,
        case AUDIO_INTERN:
        case AUDIO_RADIO:
                switch (freq) {
        case AUDIO_INTERN:
        case AUDIO_RADIO:
                switch (freq) {
-               case V4L2_AUDCLK_32_KHZ:
+               case 32000:
                        /* VID_PLL and AUX_PLL */
                        cx25840_write4(client, 0x108, 0x0f04081e);
 
                        /* VID_PLL and AUX_PLL */
                        cx25840_write4(client, 0x108, 0x0f04081e);
 
@@ -103,7 +105,7 @@ inline static int set_audclk_freq(struct i2c_client *client,
                        cx25840_write(client, 0x127, 0x54);
                        break;
 
                        cx25840_write(client, 0x127, 0x54);
                        break;
 
-               case V4L2_AUDCLK_441_KHZ:
+               case 44100:
                        /* VID_PLL and AUX_PLL */
                        cx25840_write4(client, 0x108, 0x0f040918);
 
                        /* VID_PLL and AUX_PLL */
                        cx25840_write4(client, 0x108, 0x0f040918);
 
@@ -119,7 +121,7 @@ inline static int set_audclk_freq(struct i2c_client *client,
                        cx25840_write4(client, 0x90c, 0x85730108);
                        break;
 
                        cx25840_write4(client, 0x90c, 0x85730108);
                        break;
 
-               case V4L2_AUDCLK_48_KHZ:
+               case 48000:
                        /* VID_PLL and AUX_PLL */
                        cx25840_write4(client, 0x108, 0x0f040a18);
 
                        /* VID_PLL and AUX_PLL */
                        cx25840_write4(client, 0x108, 0x0f040a18);
 
@@ -317,7 +319,7 @@ int cx25840_audio(struct i2c_client *client, unsigned int cmd, void *arg)
        case AUDC_SET_INPUT:
                return set_input(client, *(int *)arg);
        case VIDIOC_INT_AUDIO_CLOCK_FREQ:
        case AUDC_SET_INPUT:
                return set_input(client, *(int *)arg);
        case VIDIOC_INT_AUDIO_CLOCK_FREQ:
-               return set_audclk_freq(client, *(enum v4l2_audio_clock_freq *)arg);
+               return set_audclk_freq(client, *(u32 *)arg);
        case VIDIOC_G_CTRL:
                switch (ctrl->id) {
                case V4L2_CID_AUDIO_VOLUME:
        case VIDIOC_G_CTRL:
                switch (ctrl->id) {
                case V4L2_CID_AUDIO_VOLUME:
index 54ffae686dc95fae8768ee8ce55bd73738de1e17..c2c1e856aa60c6ec5dd22466710f7a8f3e580856 100644 (file)
@@ -802,7 +802,7 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address,
        i2c_set_clientdata(client, state);
        memset(state, 0, sizeof(struct cx25840_state));
        state->input = CX25840_TUNER;
        i2c_set_clientdata(client, state);
        memset(state, 0, sizeof(struct cx25840_state));
        state->input = CX25840_TUNER;
-       state->audclk_freq = V4L2_AUDCLK_48_KHZ;
+       state->audclk_freq = 48000;
        state->audio_input = AUDIO_TUNER;
        state->cardtype = CARDTYPE_PVR150;
 
        state->audio_input = AUDIO_TUNER;
        state->cardtype = CARDTYPE_PVR150;
 
@@ -1008,13 +1008,7 @@ static void log_status(struct i2c_client *client)
        cx25840_info("Specified audio input:     %s\n",
                    state->audio_input == 0 ? "Tuner" : "External");
 
        cx25840_info("Specified audio input:     %s\n",
                    state->audio_input == 0 ? "Tuner" : "External");
 
-       switch (state->audclk_freq) {
-       case V4L2_AUDCLK_441_KHZ: p = "44.1 kHz"; break;
-       case V4L2_AUDCLK_48_KHZ: p = "48 kHz"; break;
-       case V4L2_AUDCLK_32_KHZ: p = "32 kHz"; break;
-       default: p = "undefined";
-       }
-       cx25840_info("Specified audioclock freq: %s\n", p);
+       cx25840_info("Specified audioclock freq: %d Hz\n", state->audclk_freq);
 
        switch (pref_mode & 0xf) {
        case 0: p = "mono/language A"; break;
 
        switch (pref_mode & 0xf) {
        case 0: p = "mono/language A"; break;
index 40aa59f9c52595b6142f8a1f2483d2347c8bb927..4731a19092a6558cba1d301edbeec23b8bd778fd 100644 (file)
@@ -65,7 +65,7 @@ struct cx25840_state {
        enum cx25840_cardtype cardtype;
        enum cx25840_input input;
        int audio_input;
        enum cx25840_cardtype cardtype;
        enum cx25840_input input;
        int audio_input;
-       enum v4l2_audio_clock_freq audclk_freq;
+       u32 audclk_freq;
 };
 
 /* ----------------------------------------------------------------------- */
 };
 
 /* ----------------------------------------------------------------------- */
index b175389d9f43568ef0df147f550c04751686f505..3e4e5584c5d0eebe98c2b9aa3e3f2f3d29121ead 100644 (file)
@@ -39,6 +39,7 @@
 #include <linux/i2c.h>
 #include <linux/videodev2.h>
 #include <media/v4l2-common.h>
 #include <linux/i2c.h>
 #include <linux/videodev2.h>
 #include <media/v4l2-common.h>
+#include <asm/div64.h>
 
 MODULE_DESCRIPTION("Philips SAA7114/SAA7115 video decoder driver");
 MODULE_AUTHOR("Maxim Yevtyushkin, Kevin Thayer, Chris Kennedy, Hans Verkuil");
 
 MODULE_DESCRIPTION("Philips SAA7114/SAA7115 video decoder driver");
 MODULE_AUTHOR("Maxim Yevtyushkin, Kevin Thayer, Chris Kennedy, Hans Verkuil");
@@ -78,7 +79,7 @@ struct saa7115_state {
        int hue;
        int sat;
        enum v4l2_chip_ident ident;
        int hue;
        int sat;
        enum v4l2_chip_ident ident;
-       enum v4l2_audio_clock_freq audclk_freq;
+       u32 audclk_freq;
 };
 
 /* ----------------------------------------------------------------------- */
 };
 
 /* ----------------------------------------------------------------------- */
@@ -469,80 +470,6 @@ static const unsigned char saa7115_init_misc[] = {
        0x00, 0x00
 };
 
        0x00, 0x00
 };
 
-/* ============== SAA7715 AUDIO settings ============= */
-
-/* 48.0 kHz */
-static const unsigned char saa7115_cfg_48_audio[] = {
-       0x34, 0xce,
-       0x35, 0xfb,
-       0x36, 0x30,
-       0x00, 0x00
-};
-
-/* 44.1 kHz */
-static const unsigned char saa7115_cfg_441_audio[] = {
-       0x34, 0xf2,
-       0x35, 0x00,
-       0x36, 0x2d,
-       0x00, 0x00
-};
-
-/* 32.0 kHz */
-static const unsigned char saa7115_cfg_32_audio[] = {
-       0x34, 0xdf,
-       0x35, 0xa7,
-       0x36, 0x20,
-       0x00, 0x00
-};
-
-/* 48.0 kHz 60hz */
-static const unsigned char saa7115_cfg_60hz_48_audio[] = {
-       0x30, 0xcd,
-       0x31, 0x20,
-       0x32, 0x03,
-       0x00, 0x00
-};
-
-/* 48.0 kHz 50hz */
-static const unsigned char saa7115_cfg_50hz_48_audio[] = {
-       0x30, 0x00,
-       0x31, 0xc0,
-       0x32, 0x03,
-       0x00, 0x00
-};
-
-/* 44.1 kHz 60hz */
-static const unsigned char saa7115_cfg_60hz_441_audio[] = {
-       0x30, 0xbc,
-       0x31, 0xdf,
-       0x32, 0x02,
-       0x00, 0x00
-};
-
-/* 44.1 kHz 50hz */
-static const unsigned char saa7115_cfg_50hz_441_audio[] = {
-       0x30, 0x00,
-       0x31, 0x72,
-       0x32, 0x03,
-       0x00, 0x00
-};
-
-/* 32.0 kHz 60hz */
-static const unsigned char saa7115_cfg_60hz_32_audio[] = {
-       0x30, 0xde,
-       0x31, 0x15,
-       0x32, 0x02,
-       0x00, 0x00
-};
-
-/* 32.0 kHz 50hz */
-static const unsigned char saa7115_cfg_50hz_32_audio[] = {
-       0x30, 0x00,
-       0x31, 0x80,
-       0x32, 0x02,
-       0x00, 0x00
-};
-
 static int saa7115_odd_parity(u8 c)
 {
        c ^= (c >> 4);
 static int saa7115_odd_parity(u8 c)
 {
        c ^= (c >> 4);
@@ -627,40 +554,38 @@ static int saa7115_decode_wss(u8 * p)
 }
 
 
 }
 
 
-static int saa7115_set_audio_clock_freq(struct i2c_client *client, enum v4l2_audio_clock_freq freq)
+static int saa7115_set_audio_clock_freq(struct i2c_client *client, u32 freq)
 {
        struct saa7115_state *state = i2c_get_clientdata(client);
 {
        struct saa7115_state *state = i2c_get_clientdata(client);
+       u32 acpf;
+       u32 acni;
+       u32 hz;
+       u64 f;
 
        saa7115_dbg("set audio clock freq: %d\n", freq);
 
        saa7115_dbg("set audio clock freq: %d\n", freq);
-       switch (freq) {
-               case V4L2_AUDCLK_32_KHZ:
-                       saa7115_writeregs(client, saa7115_cfg_32_audio);
-                       if (state->std & V4L2_STD_525_60) {
-                               saa7115_writeregs(client, saa7115_cfg_60hz_32_audio);
-                       } else {
-                               saa7115_writeregs(client, saa7115_cfg_50hz_32_audio);
-                       }
-                       break;
-               case V4L2_AUDCLK_441_KHZ:
-                       saa7115_writeregs(client, saa7115_cfg_441_audio);
-                       if (state->std & V4L2_STD_525_60) {
-                               saa7115_writeregs(client, saa7115_cfg_60hz_441_audio);
-                       } else {
-                               saa7115_writeregs(client, saa7115_cfg_50hz_441_audio);
-                       }
-                       break;
-               case V4L2_AUDCLK_48_KHZ:
-                       saa7115_writeregs(client, saa7115_cfg_48_audio);
-                       if (state->std & V4L2_STD_525_60) {
-                               saa7115_writeregs(client, saa7115_cfg_60hz_48_audio);
-                       } else {
-                               saa7115_writeregs(client, saa7115_cfg_50hz_48_audio);
-                       }
-                       break;
-               default:
-                       saa7115_dbg("invalid audio setting %d\n", freq);
-                       return -EINVAL;
-       }
+
+       /* sanity check */
+       if (freq < 32000 || freq > 48000)
+               return -EINVAL;
+
+       /* hz is the refresh rate times 100 */
+       hz = (state->std & V4L2_STD_525_60) ? 5994 : 5000;
+       /* acpf = (256 * freq) / field_frequency == (256 * 100 * freq) / hz */
+       acpf = (25600 * freq) / hz;
+       /* acni = (256 * freq * 2^23) / crystal_frequency =
+                 (freq * 2^(8+23)) / crystal_frequency =
+                 (freq << 31) / 32.11 MHz */
+       f = freq;
+       f = f << 31;
+       do_div(f, 32110000);
+       acni = f;
+
+       saa7115_write(client, 0x30, acpf & 0xff);
+       saa7115_write(client, 0x31, (acpf >> 8) & 0xff);
+       saa7115_write(client, 0x32, (acpf >> 16) & 0x03);
+       saa7115_write(client, 0x34, acni & 0xff);
+       saa7115_write(client, 0x35, (acni >> 8) & 0xff);
+       saa7115_write(client, 0x36, (acni >> 16) & 0x3f);
        state->audclk_freq = freq;
        return 0;
 }
        state->audclk_freq = freq;
        return 0;
 }
@@ -773,24 +698,17 @@ static v4l2_std_id saa7115_get_v4lstd(struct i2c_client *client)
 static void saa7115_log_status(struct i2c_client *client)
 {
        struct saa7115_state *state = i2c_get_clientdata(client);
 static void saa7115_log_status(struct i2c_client *client)
 {
        struct saa7115_state *state = i2c_get_clientdata(client);
-       char *audfreq = "undefined";
        int reg1e, reg1f;
        int signalOk;
        int vcr;
 
        int reg1e, reg1f;
        int signalOk;
        int vcr;
 
-       switch (state->audclk_freq) {
-               case V4L2_AUDCLK_32_KHZ:  audfreq = "32 kHz"; break;
-               case V4L2_AUDCLK_441_KHZ: audfreq = "44.1 kHz"; break;
-               case V4L2_AUDCLK_48_KHZ:  audfreq = "48 kHz"; break;
-       }
-
-       saa7115_info("Audio frequency: %s\n", audfreq);
+       saa7115_info("Audio frequency: %d Hz\n", state->audclk_freq);
        if (client->name[6] == '4') {
                /* status for the saa7114 */
                reg1f = saa7115_read(client, 0x1f);
                signalOk = (reg1f & 0xc1) == 0x81;
                saa7115_info("Video signal:    %s\n", signalOk ? "ok" : "bad");
        if (client->name[6] == '4') {
                /* status for the saa7114 */
                reg1f = saa7115_read(client, 0x1f);
                signalOk = (reg1f & 0xc1) == 0x81;
                saa7115_info("Video signal:    %s\n", signalOk ? "ok" : "bad");
-               saa7115_info("Frequency:       %s\n", (reg1f & 0x20) ? "60Hz" : "50Hz");
+               saa7115_info("Frequency:       %s\n", (reg1f & 0x20) ? "60 Hz" : "50 Hz");
                return;
        }
 
                return;
        }
 
@@ -807,7 +725,7 @@ static void saa7115_log_status(struct i2c_client *client)
                saa7115_info("Input:           Composite %d\n", state->input);
        }
        saa7115_info("Video signal:    %s\n", signalOk ? (vcr ? "VCR" : "broadcast/DVD") : "bad");
                saa7115_info("Input:           Composite %d\n", state->input);
        }
        saa7115_info("Video signal:    %s\n", signalOk ? (vcr ? "VCR" : "broadcast/DVD") : "bad");
-       saa7115_info("Frequency:       %s\n", (reg1f & 0x20) ? "60Hz" : "50Hz");
+       saa7115_info("Frequency:       %s\n", (reg1f & 0x20) ? "60 Hz" : "50 Hz");
 
        switch (reg1e & 0x03) {
                case 1:
 
        switch (reg1e & 0x03) {
                case 1:
@@ -1108,7 +1026,7 @@ static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *ar
                return saa7115_get_v4lfmt(client, (struct v4l2_format *)arg);
 
        case VIDIOC_INT_AUDIO_CLOCK_FREQ:
                return saa7115_get_v4lfmt(client, (struct v4l2_format *)arg);
 
        case VIDIOC_INT_AUDIO_CLOCK_FREQ:
-               return saa7115_set_audio_clock_freq(client, *(enum v4l2_audio_clock_freq *)arg);
+               return saa7115_set_audio_clock_freq(client, *(u32 *)arg);
 
        case VIDIOC_G_TUNER:
        {
 
        case VIDIOC_G_TUNER:
        {
@@ -1307,7 +1225,7 @@ static int saa7115_attach(struct i2c_adapter *adapter, int address, int kind)
        state->hue = 0;
        state->sat = 64;
        state->ident = (chip_id == 4) ? V4L2_IDENT_SAA7114 : V4L2_IDENT_SAA7115;
        state->hue = 0;
        state->sat = 64;
        state->ident = (chip_id == 4) ? V4L2_IDENT_SAA7114 : V4L2_IDENT_SAA7115;
-       state->audclk_freq = V4L2_AUDCLK_48_KHZ;
+       state->audclk_freq = 48000;
 
        saa7115_dbg("writing init values\n");
 
 
        saa7115_dbg("writing init values\n");
 
@@ -1317,8 +1235,7 @@ static int saa7115_attach(struct i2c_adapter *adapter, int address, int kind)
        saa7115_writeregs(client, saa7115_cfg_60hz_fullres_x);
        saa7115_writeregs(client, saa7115_cfg_60hz_fullres_y);
        saa7115_writeregs(client, saa7115_cfg_60hz_video);
        saa7115_writeregs(client, saa7115_cfg_60hz_fullres_x);
        saa7115_writeregs(client, saa7115_cfg_60hz_fullres_y);
        saa7115_writeregs(client, saa7115_cfg_60hz_video);
-       saa7115_writeregs(client, saa7115_cfg_48_audio);
-       saa7115_writeregs(client, saa7115_cfg_60hz_48_audio);
+       saa7115_set_audio_clock_freq(client, state->audclk_freq);
        saa7115_writeregs(client, saa7115_cfg_reset_scaler);
 
        i2c_attach_client(client);
        saa7115_writeregs(client, saa7115_cfg_reset_scaler);
 
        i2c_attach_client(client);
index 2f2402996409af8db8618e999047086edc2173e4..90248d29ed0aa8487be9e0b0d29d9c9bd08b9114 100644 (file)
 #ifndef V4L2_COMMON_H_
 #define V4L2_COMMON_H_
 
 #ifndef V4L2_COMMON_H_
 #define V4L2_COMMON_H_
 
-/* VIDIOC_INT_AUDIO_CLOCK_FREQ */
-enum v4l2_audio_clock_freq {
-       V4L2_AUDCLK_32_KHZ  = 32000,
-       V4L2_AUDCLK_441_KHZ = 44100,
-       V4L2_AUDCLK_48_KHZ  = 48000,
-};
-
 /* VIDIOC_INT_G_REGISTER and VIDIOC_INT_S_REGISTER */
 struct v4l2_register {
        u32 i2c_id;             /* I2C driver ID of the I2C chip. 0 for the I2C adapter. */
 /* VIDIOC_INT_G_REGISTER and VIDIOC_INT_S_REGISTER */
 struct v4l2_register {
        u32 i2c_id;             /* I2C driver ID of the I2C chip. 0 for the I2C adapter. */
@@ -77,10 +70,12 @@ enum v4l2_chip_ident {
 /* Reset the I2C chip */
 #define VIDIOC_INT_RESET               _IO  ('d', 102)
 
 /* Reset the I2C chip */
 #define VIDIOC_INT_RESET               _IO  ('d', 102)
 
-/* Set the frequency of the audio clock output.
+/* Set the frequency (in Hz) of the audio clock output.
    Used to slave an audio processor to the video decoder, ensuring that audio
    Used to slave an audio processor to the video decoder, ensuring that audio
-   and video remain synchronized. */
-#define VIDIOC_INT_AUDIO_CLOCK_FREQ    _IOR ('d', 103, enum v4l2_audio_clock_freq)
+   and video remain synchronized.
+   Usual values for the frequency are 48000, 44100 or 32000 Hz.
+   If the frequency is not supported, then -EINVAL is returned. */
+#define VIDIOC_INT_AUDIO_CLOCK_FREQ    _IOW ('d', 103, u32)
 
 /* Video decoders that support sliced VBI need to implement this ioctl.
    Field p of the v4l2_sliced_vbi_line struct is set to the start of the VBI
 
 /* Video decoders that support sliced VBI need to implement this ioctl.
    Field p of the v4l2_sliced_vbi_line struct is set to the start of the VBI