Commit 3578d3dd authored by Hans Verkuil's avatar Hans Verkuil Committed by Mauro Carvalho Chehab

V4L/DVB (3214): Calculate the saa7115 AMCLK regs instead of using fixed values

- 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: default avatarHans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@brturbo.com.br>
parent 21fa715e
...@@ -23,11 +23,13 @@ ...@@ -23,11 +23,13 @@
#include "cx25840.h" #include "cx25840.h"
inline static int set_audclk_freq(struct i2c_client *client, static int set_audclk_freq(struct i2c_client *client, u32 freq)
enum v4l2_audio_clock_freq 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 */ /* assert soft reset */
cx25840_and_or(client, 0x810, ~0x1, 0x01); cx25840_and_or(client, 0x810, ~0x1, 0x01);
...@@ -38,7 +40,7 @@ inline static int set_audclk_freq(struct i2c_client *client, ...@@ -38,7 +40,7 @@ inline static int set_audclk_freq(struct i2c_client *client,
switch (state->audio_input) { switch (state->audio_input) {
case AUDIO_TUNER: case AUDIO_TUNER:
switch (freq) { switch (freq) {
case V4L2_AUDCLK_32_KHZ: case 32000:
/* VID_PLL and AUX_PLL */ /* VID_PLL and AUX_PLL */
cx25840_write4(client, 0x108, 0x0f040610); cx25840_write4(client, 0x108, 0x0f040610);
...@@ -51,7 +53,7 @@ inline static int set_audclk_freq(struct i2c_client *client, ...@@ -51,7 +53,7 @@ inline static int set_audclk_freq(struct i2c_client *client,
cx25840_write4(client, 0x90c, 0x7ff70108); cx25840_write4(client, 0x90c, 0x7ff70108);
break; break;
case V4L2_AUDCLK_441_KHZ: case 44100:
/* VID_PLL and AUX_PLL */ /* VID_PLL and AUX_PLL */
cx25840_write4(client, 0x108, 0x0f040910); cx25840_write4(client, 0x108, 0x0f040910);
...@@ -64,7 +66,7 @@ inline static int set_audclk_freq(struct i2c_client *client, ...@@ -64,7 +66,7 @@ inline static int set_audclk_freq(struct i2c_client *client,
cx25840_write4(client, 0x90c, 0x596d0108); cx25840_write4(client, 0x90c, 0x596d0108);
break; break;
case V4L2_AUDCLK_48_KHZ: case 48000:
/* VID_PLL and AUX_PLL */ /* VID_PLL and AUX_PLL */
cx25840_write4(client, 0x108, 0x0f040a10); cx25840_write4(client, 0x108, 0x0f040a10);
...@@ -84,7 +86,7 @@ inline static int set_audclk_freq(struct i2c_client *client, ...@@ -84,7 +86,7 @@ inline static int set_audclk_freq(struct i2c_client *client,
case AUDIO_INTERN: case AUDIO_INTERN:
case AUDIO_RADIO: case AUDIO_RADIO:
switch (freq) { switch (freq) {
case V4L2_AUDCLK_32_KHZ: case 32000:
/* VID_PLL and AUX_PLL */ /* VID_PLL and AUX_PLL */
cx25840_write4(client, 0x108, 0x0f04081e); cx25840_write4(client, 0x108, 0x0f04081e);
...@@ -103,7 +105,7 @@ inline static int set_audclk_freq(struct i2c_client *client, ...@@ -103,7 +105,7 @@ inline static int set_audclk_freq(struct i2c_client *client,
cx25840_write(client, 0x127, 0x54); cx25840_write(client, 0x127, 0x54);
break; break;
case V4L2_AUDCLK_441_KHZ: case 44100:
/* VID_PLL and AUX_PLL */ /* VID_PLL and AUX_PLL */
cx25840_write4(client, 0x108, 0x0f040918); cx25840_write4(client, 0x108, 0x0f040918);
...@@ -119,7 +121,7 @@ inline static int set_audclk_freq(struct i2c_client *client, ...@@ -119,7 +121,7 @@ inline static int set_audclk_freq(struct i2c_client *client,
cx25840_write4(client, 0x90c, 0x85730108); cx25840_write4(client, 0x90c, 0x85730108);
break; break;
case V4L2_AUDCLK_48_KHZ: case 48000:
/* VID_PLL and AUX_PLL */ /* VID_PLL and AUX_PLL */
cx25840_write4(client, 0x108, 0x0f040a18); cx25840_write4(client, 0x108, 0x0f040a18);
...@@ -317,7 +319,7 @@ int cx25840_audio(struct i2c_client *client, unsigned int cmd, void *arg) ...@@ -317,7 +319,7 @@ int cx25840_audio(struct i2c_client *client, unsigned int cmd, void *arg)
case AUDC_SET_INPUT: case AUDC_SET_INPUT:
return set_input(client, *(int *)arg); return set_input(client, *(int *)arg);
case VIDIOC_INT_AUDIO_CLOCK_FREQ: 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: case VIDIOC_G_CTRL:
switch (ctrl->id) { switch (ctrl->id) {
case V4L2_CID_AUDIO_VOLUME: case V4L2_CID_AUDIO_VOLUME:
......
...@@ -802,7 +802,7 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address, ...@@ -802,7 +802,7 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address,
i2c_set_clientdata(client, state); i2c_set_clientdata(client, state);
memset(state, 0, sizeof(struct cx25840_state)); memset(state, 0, sizeof(struct cx25840_state));
state->input = CX25840_TUNER; state->input = CX25840_TUNER;
state->audclk_freq = V4L2_AUDCLK_48_KHZ; state->audclk_freq = 48000;
state->audio_input = AUDIO_TUNER; state->audio_input = AUDIO_TUNER;
state->cardtype = CARDTYPE_PVR150; state->cardtype = CARDTYPE_PVR150;
...@@ -1008,13 +1008,7 @@ static void log_status(struct i2c_client *client) ...@@ -1008,13 +1008,7 @@ static void log_status(struct i2c_client *client)
cx25840_info("Specified audio input: %s\n", cx25840_info("Specified audio input: %s\n",
state->audio_input == 0 ? "Tuner" : "External"); state->audio_input == 0 ? "Tuner" : "External");
switch (state->audclk_freq) { cx25840_info("Specified audioclock freq: %d Hz\n", 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);
switch (pref_mode & 0xf) { switch (pref_mode & 0xf) {
case 0: p = "mono/language A"; break; case 0: p = "mono/language A"; break;
......
...@@ -65,7 +65,7 @@ struct cx25840_state { ...@@ -65,7 +65,7 @@ struct cx25840_state {
enum cx25840_cardtype cardtype; enum cx25840_cardtype cardtype;
enum cx25840_input input; enum cx25840_input input;
int audio_input; int audio_input;
enum v4l2_audio_clock_freq audclk_freq; u32 audclk_freq;
}; };
/* ----------------------------------------------------------------------- */ /* ----------------------------------------------------------------------- */
......
...@@ -39,6 +39,7 @@ ...@@ -39,6 +39,7 @@
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/videodev2.h> #include <linux/videodev2.h>
#include <media/v4l2-common.h> #include <media/v4l2-common.h>
#include <asm/div64.h>
MODULE_DESCRIPTION("Philips SAA7114/SAA7115 video decoder driver"); MODULE_DESCRIPTION("Philips SAA7114/SAA7115 video decoder driver");
MODULE_AUTHOR("Maxim Yevtyushkin, Kevin Thayer, Chris Kennedy, Hans Verkuil"); MODULE_AUTHOR("Maxim Yevtyushkin, Kevin Thayer, Chris Kennedy, Hans Verkuil");
...@@ -78,7 +79,7 @@ struct saa7115_state { ...@@ -78,7 +79,7 @@ struct saa7115_state {
int hue; int hue;
int sat; int sat;
enum v4l2_chip_ident ident; 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[] = { ...@@ -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) static int saa7115_odd_parity(u8 c)
{ {
c ^= (c >> 4); c ^= (c >> 4);
...@@ -627,40 +554,38 @@ static int saa7115_decode_wss(u8 * p) ...@@ -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: /* sanity check */
saa7115_writeregs(client, saa7115_cfg_32_audio); if (freq < 32000 || freq > 48000)
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; 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; state->audclk_freq = freq;
return 0; return 0;
} }
...@@ -773,24 +698,17 @@ static v4l2_std_id saa7115_get_v4lstd(struct i2c_client *client) ...@@ -773,24 +698,17 @@ static v4l2_std_id saa7115_get_v4lstd(struct i2c_client *client)
static void saa7115_log_status(struct i2c_client *client) static void saa7115_log_status(struct i2c_client *client)
{ {
struct saa7115_state *state = i2c_get_clientdata(client); struct saa7115_state *state = i2c_get_clientdata(client);
char *audfreq = "undefined";
int reg1e, reg1f; int reg1e, reg1f;
int signalOk; int signalOk;
int vcr; int vcr;
switch (state->audclk_freq) { saa7115_info("Audio frequency: %d Hz\n", 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);
if (client->name[6] == '4') { if (client->name[6] == '4') {
/* status for the saa7114 */ /* status for the saa7114 */
reg1f = saa7115_read(client, 0x1f); reg1f = saa7115_read(client, 0x1f);
signalOk = (reg1f & 0xc1) == 0x81; signalOk = (reg1f & 0xc1) == 0x81;
saa7115_info("Video signal: %s\n", signalOk ? "ok" : "bad"); 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) ...@@ -807,7 +725,7 @@ static void saa7115_log_status(struct i2c_client *client)
saa7115_info("Input: Composite %d\n", state->input); saa7115_info("Input: Composite %d\n", state->input);
} }
saa7115_info("Video signal: %s\n", signalOk ? (vcr ? "VCR" : "broadcast/DVD") : "bad"); 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) { switch (reg1e & 0x03) {
case 1: case 1:
...@@ -1108,7 +1026,7 @@ static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *ar ...@@ -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); return saa7115_get_v4lfmt(client, (struct v4l2_format *)arg);
case VIDIOC_INT_AUDIO_CLOCK_FREQ: 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) ...@@ -1307,7 +1225,7 @@ static int saa7115_attach(struct i2c_adapter *adapter, int address, int kind)
state->hue = 0; state->hue = 0;
state->sat = 64; state->sat = 64;
state->ident = (chip_id == 4) ? V4L2_IDENT_SAA7114 : V4L2_IDENT_SAA7115; 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) ...@@ -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_x);
saa7115_writeregs(client, saa7115_cfg_60hz_fullres_y); saa7115_writeregs(client, saa7115_cfg_60hz_fullres_y);
saa7115_writeregs(client, saa7115_cfg_60hz_video); saa7115_writeregs(client, saa7115_cfg_60hz_video);
saa7115_writeregs(client, saa7115_cfg_48_audio); saa7115_set_audio_clock_freq(client, state->audclk_freq);
saa7115_writeregs(client, saa7115_cfg_60hz_48_audio);
saa7115_writeregs(client, saa7115_cfg_reset_scaler); saa7115_writeregs(client, saa7115_cfg_reset_scaler);
i2c_attach_client(client); i2c_attach_client(client);
......
...@@ -26,13 +26,6 @@ ...@@ -26,13 +26,6 @@
#ifndef V4L2_COMMON_H_ #ifndef V4L2_COMMON_H_
#define 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 */ /* VIDIOC_INT_G_REGISTER and VIDIOC_INT_S_REGISTER */
struct v4l2_register { struct v4l2_register {
u32 i2c_id; /* I2C driver ID of the I2C chip. 0 for the I2C adapter. */ u32 i2c_id; /* I2C driver ID of the I2C chip. 0 for the I2C adapter. */
...@@ -77,10 +70,12 @@ enum v4l2_chip_ident { ...@@ -77,10 +70,12 @@ enum v4l2_chip_ident {
/* Reset the I2C chip */ /* Reset the I2C chip */
#define VIDIOC_INT_RESET _IO ('d', 102) #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. */ and video remain synchronized.
#define VIDIOC_INT_AUDIO_CLOCK_FREQ _IOR ('d', 103, enum v4l2_audio_clock_freq) 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. /* 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 Field p of the v4l2_sliced_vbi_line struct is set to the start of the VBI
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment