#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);
 
+       if (freq != 32000 && freq != 44100 && freq != 48000)
+               return -EINVAL;
+
        /* assert soft reset */
        cx25840_and_or(client, 0x810, ~0x1, 0x01);
 
        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);
 
                        cx25840_write4(client, 0x90c, 0x7ff70108);
                        break;
 
-               case V4L2_AUDCLK_441_KHZ:
+               case 44100:
                        /* VID_PLL and AUX_PLL */
                        cx25840_write4(client, 0x108, 0x0f040910);
 
                        cx25840_write4(client, 0x90c, 0x596d0108);
                        break;
 
-               case V4L2_AUDCLK_48_KHZ:
+               case 48000:
                        /* VID_PLL and AUX_PLL */
                        cx25840_write4(client, 0x108, 0x0f040a10);
 
        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);
 
                        cx25840_write(client, 0x127, 0x54);
                        break;
 
-               case V4L2_AUDCLK_441_KHZ:
+               case 44100:
                        /* VID_PLL and AUX_PLL */
                        cx25840_write4(client, 0x108, 0x0f040918);
 
                        cx25840_write4(client, 0x90c, 0x85730108);
                        break;
 
-               case V4L2_AUDCLK_48_KHZ:
+               case 48000:
                        /* VID_PLL and AUX_PLL */
                        cx25840_write4(client, 0x108, 0x0f040a18);
 
        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:
 
 #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");
        int hue;
        int sat;
        enum v4l2_chip_ident ident;
-       enum v4l2_audio_clock_freq audclk_freq;
+       u32 audclk_freq;
 };
 
 /* ----------------------------------------------------------------------- */
        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_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);
+       u32 acpf;
+       u32 acni;
+       u32 hz;
+       u64 f;
 
        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;
 }
 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;
 
-       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");
-               saa7115_info("Frequency:       %s\n", (reg1f & 0x20) ? "60Hz" : "50Hz");
+               saa7115_info("Frequency:       %s\n", (reg1f & 0x20) ? "60 Hz" : "50 Hz");
                return;
        }
 
                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:
                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:
        {
        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_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);
 
 #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. */
 /* 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
-   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