summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHans Verkuil <hverkuil@xs4all.nl>2006-04-02 17:50:42 +0200
committerHans Verkuil <hverkuil@xs4all.nl>2006-04-02 17:50:42 +0200
commit7d27e5f3b2bbe8ca82a41dce5203a67d7595ab09 (patch)
tree61df08b6032aee1f880e3a1987019b542aee8c31
parent33ba11f17dbf2c000c797475db2c6b68b7d33662 (diff)
downloadmediapointer-dvb-s2-7d27e5f3b2bbe8ca82a41dce5203a67d7595ab09.tar.gz
mediapointer-dvb-s2-7d27e5f3b2bbe8ca82a41dce5203a67d7595ab09.tar.bz2
Add support for VIDIOC_INT_S_CRYSTAL_FREQ internal command.
From: Hans Verkuil <hverkuil@xs4all.nl> Some saa7115-based cards use a different crystal frequency and a different audio clock generation. Add a new VIDIOC_INT_S_CRYSTAL_FREQ command to be able to set these values. Also change the default APLL setting to 0. It makes no sense to have the audio clock independent from the video clock, this can lead to audio/video synchronization problems. Setting this to 0 is also consistent with the old saa7114.c source and the way the Hauppauge Windows driver sets it. Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
-rw-r--r--linux/drivers/media/video/saa7115.c51
-rw-r--r--linux/drivers/media/video/v4l2-common.c9
-rw-r--r--linux/include/media/saa7115.h11
-rw-r--r--linux/include/media/v4l2-common.h11
4 files changed, 72 insertions, 10 deletions
diff --git a/linux/drivers/media/video/saa7115.c b/linux/drivers/media/video/saa7115.c
index 1ecfacea5..6c40aa397 100644
--- a/linux/drivers/media/video/saa7115.c
+++ b/linux/drivers/media/video/saa7115.c
@@ -83,6 +83,10 @@ struct saa7115_state {
int sat;
enum v4l2_chip_ident ident;
u32 audclk_freq;
+ u32 crystal_freq;
+ u8 ucgc;
+ u8 cgcdiv;
+ u8 apll;
};
/* ----------------------------------------------------------------------- */
@@ -388,10 +392,6 @@ static const unsigned char saa7113_init_auto_input[] = {
#endif
static const unsigned char saa7115_init_misc[] = {
- 0x38, 0x03, /* audio stuff */
- 0x39, 0x10,
- 0x3a, 0x08,
-
0x81, 0x01, /* reg 0x15,0x16 define blanking window */
0x82, 0x00,
0x83, 0x01, /* I port settings */
@@ -597,6 +597,7 @@ static int saa7115_set_audio_clock_freq(struct i2c_client *client, u32 freq)
u32 acni;
u32 hz;
u64 f;
+ u8 acc = 0; /* reg 0x3a, audio clock control */
v4l_dbg(1, debug, client, "set audio clock freq: %d\n", freq);
@@ -604,18 +605,34 @@ static int saa7115_set_audio_clock_freq(struct i2c_client *client, u32 freq)
if (freq < 32000 || freq > 48000)
return -EINVAL;
+ /* The saa7113 has no audio clock */
+ if (state->ident == V4L2_IDENT_SAA7113)
+ return 0;
+
/* 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 */
+ (freq << 31) / crystal_frequency */
f = freq;
f = f << 31;
- do_div(f, 32110000);
+ do_div(f, state->crystal_freq);
acni = f;
+ if (state->ucgc) {
+ acpf = acpf * state->cgcdiv / 16;
+ acni = acni * state->cgcdiv / 16;
+ acc = 0x80;
+ if (state->cgcdiv == 3)
+ acc |= 0x40;
+ }
+ if (state->apll)
+ acc |= 0x08;
+ saa7115_write(client, 0x38, 0x03);
+ saa7115_write(client, 0x39, 0x10);
+ saa7115_write(client, 0x3a, acc);
saa7115_write(client, 0x30, acpf & 0xff);
saa7115_write(client, 0x31, (acpf >> 8) & 0xff);
saa7115_write(client, 0x32, (acpf >> 16) & 0x03);
@@ -1273,6 +1290,21 @@ static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *ar
}
break;
+ case VIDIOC_INT_S_CRYSTAL_FREQ:
+ {
+ struct v4l2_crystal_freq *freq = arg;
+
+ if (freq->freq != SAA7115_FREQ_32_11_MHZ &&
+ freq->freq != SAA7115_FREQ_24_576_MHZ)
+ return -EINVAL;
+ state->crystal_freq = freq->freq;
+ state->cgcdiv = (freq->flags & SAA7115_FREQ_FL_CGCDIV) ? 3 : 4;
+ state->ucgc = (freq->flags & SAA7115_FREQ_FL_UCGC) ? 1 : 0;
+ state->apll = (freq->flags & SAA7115_FREQ_FL_APLL) ? 1 : 0;
+ saa7115_set_audio_clock_freq(client, state->audclk_freq);
+ break;
+ }
+
case VIDIOC_INT_DECODE_VBI_LINE:
saa7115_decode_vbi_line(client, arg);
break;
@@ -1422,10 +1454,13 @@ static int saa7115_attach(struct i2c_adapter *adapter, int address, int kind)
v4l_dbg(1, debug, client, "writing init values\n");
/* init to 60hz/48khz */
- if (state->ident == V4L2_IDENT_SAA7113)
+ if (state->ident == V4L2_IDENT_SAA7113) {
+ state->crystal_freq = SAA7115_FREQ_24_576_MHZ;
saa7115_writeregs(client, saa7113_init_auto_input);
- else
+ } else {
+ state->crystal_freq = SAA7115_FREQ_32_11_MHZ;
saa7115_writeregs(client, saa7115_init_auto_input);
+ }
saa7115_writeregs(client, saa7115_init_misc);
saa7115_writeregs(client, saa7115_cfg_60hz_fullres_x);
saa7115_writeregs(client, saa7115_cfg_60hz_fullres_y);
diff --git a/linux/drivers/media/video/v4l2-common.c b/linux/drivers/media/video/v4l2-common.c
index 5f71edf32..4b7ef8350 100644
--- a/linux/drivers/media/video/v4l2-common.c
+++ b/linux/drivers/media/video/v4l2-common.c
@@ -351,7 +351,8 @@ static const char *v4l2_int_ioctls[] = {
[_IOC_NR(VIDIOC_INT_S_AUDIO_ROUTING)] = "VIDIOC_INT_S_AUDIO_ROUTING",
[_IOC_NR(VIDIOC_INT_G_AUDIO_ROUTING)] = "VIDIOC_INT_G_AUDIO_ROUTING",
[_IOC_NR(VIDIOC_INT_S_VIDEO_ROUTING)] = "VIDIOC_INT_S_VIDEO_ROUTING",
- [_IOC_NR(VIDIOC_INT_G_VIDEO_ROUTING)] = "VIDIOC_INT_G_VIDEO_ROUTING"
+ [_IOC_NR(VIDIOC_INT_G_VIDEO_ROUTING)] = "VIDIOC_INT_G_VIDEO_ROUTING",
+ [_IOC_NR(VIDIOC_INT_S_CRYSTAL_FREQ)] = "VIDIOC_INT_S_CRYSTAL_FREQ"
};
#define V4L2_INT_IOCTLS ARRAY_SIZE(v4l2_int_ioctls)
@@ -698,6 +699,12 @@ void v4l_printk_ioctl_arg(char *s,unsigned int cmd, void *arg)
printk ("%s: input=0x%x, output=0x%x\n", s, p->input, p->output);
break;
}
+ case VIDIOC_INT_S_CRYSTAL_FREQ:
+ {
+ struct v4l2_crystal_freq *p=arg;
+ printk ("%s: freq=%u, flags=0x%x\n", s, p->freq, p->flags);
+ break;
+ }
case VIDIOC_G_SLICED_VBI_CAP:
{
struct v4l2_sliced_vbi_cap *p=arg;
diff --git a/linux/include/media/saa7115.h b/linux/include/media/saa7115.h
index 6b4836f3f..9f0e2285a 100644
--- a/linux/include/media/saa7115.h
+++ b/linux/include/media/saa7115.h
@@ -1,5 +1,5 @@
/*
- saa7115.h - definition for saa7113/4/5 inputs
+ saa7115.h - definition for saa7113/4/5 inputs and frequency flags
Copyright (C) 2006 Hans Verkuil (hverkuil@xs4all.nl)
@@ -33,5 +33,14 @@
#define SAA7115_SVIDEO2 8
#define SAA7115_SVIDEO3 9
+/* SAA7115 v4l2_crystal_freq frequency values */
+#define SAA7115_FREQ_32_11_MHZ 32110000 /* 32.11 MHz crystal, SAA7114/5 only */
+#define SAA7115_FREQ_24_576_MHZ 24576000 /* 24.576 MHz crystal */
+
+/* SAA7115 v4l2_crystal_freq audio clock control flags */
+#define SAA7115_FREQ_FL_UCGC (1 << 0) /* SA 3A[7], UCGC, SAA7115 only */
+#define SAA7115_FREQ_FL_CGCDIV (1 << 1) /* SA 3A[6], CGCDIV, SAA7115 only */
+#define SAA7115_FREQ_FL_APLL (1 << 2) /* SA 3A[3], APLL, SAA7114/5 only */
+
#endif
diff --git a/linux/include/media/v4l2-common.h b/linux/include/media/v4l2-common.h
index 60c0bc91e..6ffa8eabb 100644
--- a/linux/include/media/v4l2-common.h
+++ b/linux/include/media/v4l2-common.h
@@ -217,4 +217,15 @@ struct v4l2_routing {
#define VIDIOC_INT_S_VIDEO_ROUTING _IOW ('d', 111, struct v4l2_routing)
#define VIDIOC_INT_G_VIDEO_ROUTING _IOR ('d', 112, struct v4l2_routing)
+struct v4l2_crystal_freq {
+ u32 freq; /* frequency in Hz of the crystal */
+ u32 flags; /* device specific flags */
+};
+
+/* Sets the frequency of the crystal used to generate the clocks.
+ An extra flags field allows device specific configuration regarding
+ clock frequency dividers, etc. If not used, then set flags to 0.
+ If the frequency is not supported, then -EINVAL is returned. */
+#define VIDIOC_INT_S_CRYSTAL_FREQ _IOW ('d', 113, struct v4l2_crystal_freq)
+
#endif /* V4L2_COMMON_H_ */