Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+11 −9
Original line number Diff line number Diff line
@@ -23,11 +23,13 @@

#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);

@@ -38,7 +40,7 @@ inline static int set_audclk_freq(struct i2c_client *client,
	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);

@@ -51,7 +53,7 @@ inline static int set_audclk_freq(struct i2c_client *client,
			cx25840_write4(client, 0x90c, 0x7ff70108);
			break;

		case V4L2_AUDCLK_441_KHZ:
		case 44100:
			/* 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;

		case V4L2_AUDCLK_48_KHZ:
		case 48000:
			/* 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 V4L2_AUDCLK_32_KHZ:
		case 32000:
			/* 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;

		case V4L2_AUDCLK_441_KHZ:
		case 44100:
			/* 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;

		case V4L2_AUDCLK_48_KHZ:
		case 48000:
			/* 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:
		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:
+2 −8
Original line number Diff line number Diff line
@@ -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;
	state->audclk_freq = V4L2_AUDCLK_48_KHZ;
	state->audclk_freq = 48000;
	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");

	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;
+1 −1
Original line number Diff line number Diff line
@@ -65,7 +65,7 @@ struct cx25840_state {
	enum cx25840_cardtype cardtype;
	enum cx25840_input input;
	int audio_input;
	enum v4l2_audio_clock_freq audclk_freq;
	u32 audclk_freq;
};

/* ----------------------------------------------------------------------- */
+36 −119
Original line number Diff line number Diff line
@@ -39,6 +39,7 @@
#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");
@@ -78,7 +79,7 @@ struct saa7115_state {
	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
};

/* ============== 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);
@@ -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);
	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);

	/* 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;
}
@@ -773,18 +698,11 @@ 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);
	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);
@@ -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_set_audio_clock_freq(client, *(enum v4l2_audio_clock_freq *)arg);
		return saa7115_set_audio_clock_freq(client, *(u32 *)arg);

	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->audclk_freq = V4L2_AUDCLK_48_KHZ;
	state->audclk_freq = 48000;

	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_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);
+5 −10
Original line number Diff line number Diff line
@@ -26,13 +26,6 @@
#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. */
@@ -77,10 +70,12 @@ enum v4l2_chip_ident {
/* 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