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

Commit 7560d7a4 authored by Hans Verkuil's avatar Hans Verkuil Committed by Mauro Carvalho Chehab
Browse files

V4L/DVB (3317): msp3400: use v4l2_std_id and determine chip capabilities.



- Replace old norm by the v4l2_std_id values.
- Add code to correctly detect the various capabilities of the
various msp chips. It's not yet used, that's going to be the next step.

Signed-off-by: default avatarHans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@brturbo.com.br>
parent 3d7d027a
Loading
Loading
Loading
Loading
+67 −53
Original line number Diff line number Diff line
@@ -312,10 +312,16 @@ void msp_set_audio(struct i2c_client *client)
	msp_write_dsp(client, 0x0003, treble); /* loudspeaker */
}

int msp_modus(struct i2c_client *client, int norm)
int msp_modus(struct i2c_client *client)
{
	switch (norm) {
	case VIDEO_MODE_PAL:
	struct msp_state *state = i2c_get_clientdata(client);

	if (state->radio) {
		v4l_dbg(1, client, "video mode selected to Radio\n");
		return 0x0003;
	}

	if (state->std & V4L2_STD_PAL) {
		v4l_dbg(1, client, "video mode selected to PAL\n");

#if 1
@@ -325,37 +331,16 @@ int msp_modus(struct i2c_client *client, int norm)
		/* previous value, try this if it breaks ... */
		return 0x1003;
#endif
	case VIDEO_MODE_NTSC:  /* BTSC */
	}
	if (state->std & V4L2_STD_NTSC) {
		v4l_dbg(1, client, "video mode selected to NTSC\n");
		return 0x2003;
	case VIDEO_MODE_SECAM:
	}
	if (state->std & V4L2_STD_SECAM) {
		v4l_dbg(1, client, "video mode selected to SECAM\n");
		return 0x0003;
	case VIDEO_MODE_RADIO:
		v4l_dbg(1, client, "video mode selected to Radio\n");
		return 0x0003;
	case VIDEO_MODE_AUTO:
		v4l_dbg(1, client, "video mode selected to Auto\n");
		return 0x2003;
	default:
		return 0x0003;
	}
}

int msp_standard(int norm)
{
	switch (norm) {
	case VIDEO_MODE_PAL:
		return 1;
	case VIDEO_MODE_NTSC:  /* BTSC */
		return 0x0020;
	case VIDEO_MODE_SECAM:
		return 1;
	case VIDEO_MODE_RADIO:
		return 0x0040;
	default:
		return 1;
	}
	return 0x0003;
}

/* ------------------------------------------------------------------------ */
@@ -617,7 +602,7 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
		break;

	case AUDC_SET_RADIO:
		state->norm = VIDEO_MODE_RADIO;
		state->radio = 1;
		v4l_dbg(1, client, "switching to radio mode\n");
		state->watch_stereo = 0;
		switch (state->opmode) {
@@ -673,7 +658,7 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
		state->treble = va->treble;
		msp_set_audio(client);

		if (va->mode != 0 && state->norm != VIDEO_MODE_RADIO)
		if (va->mode != 0 && state->radio == 0)
			msp_any_set_audmode(client, msp_mode_v4l1_to_v4l2(va->mode));
		break;
	}
@@ -682,7 +667,13 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
	{
		struct video_channel *vc = arg;

		state->norm = vc->norm;
		state->radio = 0;
		if (vc->norm == VIDEO_MODE_PAL)
			state->std = V4L2_STD_PAL;
		else if (vc->norm == VIDEO_MODE_SECAM)
			state->std = V4L2_STD_SECAM;
		else
			state->std = V4L2_STD_NTSC;
		msp_wake_thread(client);
		break;
	}
@@ -709,15 +700,8 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
	{
		v4l2_std_id *id = arg;

		/*FIXME: use V4L2 mode flags on msp3400 instead of V4L1*/
		if (*id & V4L2_STD_PAL) {
			state->norm = VIDEO_MODE_PAL;
		} else if (*id & V4L2_STD_SECAM) {
			state->norm = VIDEO_MODE_SECAM;
		} else {
			state->norm = VIDEO_MODE_NTSC;
		}

		state->std = *id;
		state->radio = 0;
		msp_wake_thread(client);
		return 0;
	}
@@ -965,6 +949,11 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind)
	struct i2c_client *client;
	struct msp_state *state;
	int (*thread_func)(void *data) = NULL;
	int msp_hard;
	int msp_family;
	int msp_revision;
	int msp_product, msp_prod_hi, msp_prod_lo;
	int msp_rom;

	client = kmalloc(sizeof(*client), GFP_KERNEL);
	if (client == NULL)
@@ -989,7 +978,7 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind)
	i2c_set_clientdata(client, state);

	memset(state, 0, sizeof(*state));
	state->norm = VIDEO_MODE_NTSC;
	state->std = V4L2_STD_NTSC;
	state->volume = 58880;	/* 0db gain */
	state->balance = 32768;	/* 0db gain */
	state->bass = 32768;
@@ -1012,20 +1001,45 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind)

	msp_set_audio(client);

	snprintf(client->name, sizeof(client->name), "MSP%c4%02d%c-%c%d",
		 ((state->rev1 >> 4) & 0x0f) + '3',
		 (state->rev2 >> 8) & 0xff,
		 (state->rev1 & 0x0f) + '@',
		 ((state->rev1 >> 8) & 0xff) + '@',
		 state->rev2 & 0x1f);
	msp_family = ((state->rev1 >> 4) & 0x0f) + 3;
	msp_product = (state->rev2 >> 8) & 0xff;
	msp_prod_hi = msp_product / 10;
	msp_prod_lo = msp_product % 10;
	msp_revision = (state->rev1 & 0x0f) + '@';
	msp_hard = ((state->rev1 >> 8) & 0xff) + '@';
	msp_rom = state->rev2 & 0x1f;
	snprintf(client->name, sizeof(client->name), "MSP%d4%02d%c-%c%d",
			msp_family, msp_product,
			msp_revision, msp_hard, msp_rom);

	/* Has NICAM support: all mspx41x and mspx45x products have NICAM */
	state->has_nicam = msp_prod_hi == 1 || msp_prod_hi == 5;
	/* Has radio support: was added with revision G */
	state->has_radio = msp_revision >= 'G';
	/* Has headphones output: not for stripped down products */
	state->has_headphones = msp_prod_lo < 5;
	/* Has scart4 input: not in pre D revisions, not in stripped D revs */
	state->has_scart4 = msp_family >= 4 || (msp_revision >= 'D' && msp_prod_lo < 5);
	/* Has scart2 and scart3 inputs and scart2 output: not in stripped
	   down products of the '3' family */
	state->has_scart23_in_scart2_out = msp_family >= 4 || msp_prod_lo < 5;
	/* Has subwoofer output: not in pre-D revs and not in stripped down products */
	state->has_subwoofer = msp_revision >= 'D' && msp_prod_lo < 5;
	/* Has soundprocessing (bass/treble/balance/loudness/equalizer): not in
	   stripped down products */
	state->has_sound_processing = msp_prod_lo < 7;
	/* Has Virtual Dolby Surround: only in msp34x1 */
	state->has_virtual_dolby_surround = msp_revision == 'G' && msp_prod_lo == 1;
	/* Has Virtual Dolby Surround & Dolby Pro Logic: only in msp34x2 */
	state->has_dolby_pro_logic = msp_revision == 'G' && msp_prod_lo == 2;

	state->opmode = opmode;
	if (state->opmode == OPMODE_AUTO) {
		/* MSP revision G and up have both autodetect and autoselect */
		if ((state->rev1 & 0x0f) >= 'G'-'@')
		if (msp_revision >= 'G')
			state->opmode = OPMODE_AUTOSELECT;
		/* MSP revision D and up have autodetect */
		else if ((state->rev1 & 0x0f) >= 'D'-'@')
		else if (msp_revision >= 'D')
			state->opmode = OPMODE_AUTODETECT;
		else
			state->opmode = OPMODE_MANUAL;
@@ -1034,11 +1048,11 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind)
	/* hello world :-) */
	v4l_info(client, "%s found @ 0x%x (%s)\n", client->name, address << 1, adapter->name);
	v4l_info(client, "%s ", client->name);
	if (HAVE_NICAM(state) && HAVE_RADIO(state))
	if (state->has_nicam && state->has_radio)
		printk("supports nicam and radio, ");
	else if (HAVE_NICAM(state))
	else if (state->has_nicam)
		printk("supports nicam, ");
	else if (HAVE_RADIO(state))
	else if (state->has_radio)
		printk("supports radio, ");
	printk("mode is ");

+17 −16
Original line number Diff line number Diff line
@@ -203,7 +203,7 @@ void msp3400c_setmode(struct i2c_client *client, int type)
	msp_write_dsp(client, 0x000a, msp3400c_init_data[type].dsp_src);
	msp_write_dsp(client, 0x000e, msp3400c_init_data[type].dsp_matrix);

	if (HAVE_NICAM(state)) {
	if (state->has_nicam) {
		/* nicam prescale */
		msp_write_dsp(client, 0x0010, 0x5a00); /* was: 0x3000 */
	}
@@ -487,8 +487,7 @@ int msp3400c_thread(void *data)
		if (kthread_should_stop())
			break;

		if (VIDEO_MODE_RADIO == state->norm ||
		    MSP_MODE_EXTERN  == state->mode) {
		if (state->radio || MSP_MODE_EXTERN == state->mode) {
			/* no carrier scan, just unmute */
			v4l_dbg(1, client, "thread: no carrier scan\n");
			msp_set_audio(client);
@@ -510,7 +509,7 @@ int msp3400c_thread(void *data)
		cd = msp3400c_carrier_detect_main;
		count = ARRAY_SIZE(msp3400c_carrier_detect_main);

		if (amsound && (state->norm == VIDEO_MODE_SECAM)) {
		if (amsound && (state->std & V4L2_STD_SECAM)) {
			/* autodetect doesn't work well with AM ... */
			max1 = 3;
			count = 0;
@@ -547,7 +546,7 @@ int msp3400c_thread(void *data)
			break;
		}

		if (amsound && (state->norm == VIDEO_MODE_SECAM)) {
		if (amsound && (state->std & V4L2_STD_SECAM)) {
			/* autodetect doesn't work well with AM ... */
			cd = NULL;
			count = 0;
@@ -576,7 +575,7 @@ int msp3400c_thread(void *data)
				state->nicam_on = 0;
				msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO);
				state->watch_stereo = 1;
			} else if (max2 == 1 && HAVE_NICAM(state)) {
			} else if (max2 == 1 && state->has_nicam) {
				/* B/G NICAM */
				state->second = msp3400c_carrier_detect_55[max2].cdo;
				msp3400c_setmode(client, MSP_MODE_FM_NICAM1);
@@ -603,8 +602,7 @@ int msp3400c_thread(void *data)
				state->nicam_on = 0;
				msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO);
				state->watch_stereo = 1;
			} else if (max2 == 0 &&
				   state->norm == VIDEO_MODE_SECAM) {
			} else if (max2 == 0 && (state->std & V4L2_STD_SECAM)) {
				/* L NICAM or AM-mono */
				state->second = msp3400c_carrier_detect_65[max2].cdo;
				msp3400c_setmode(client, MSP_MODE_AM_NICAM);
@@ -614,7 +612,7 @@ int msp3400c_thread(void *data)
				/* volume prescale for SCART (AM mono input) */
				msp_write_dsp(client, 0x000d, 0x1900);
				state->watch_stereo = 1;
			} else if (max2 == 0 && HAVE_NICAM(state)) {
			} else if (max2 == 0 && state->has_nicam) {
				/* D/K NICAM */
				state->second = msp3400c_carrier_detect_65[max2].cdo;
				msp3400c_setmode(client, MSP_MODE_FM_NICAM1);
@@ -689,8 +687,8 @@ int msp3410d_thread(void *data)
			goto restart;

		/* start autodetect */
		mode = msp_modus(client, state->norm);
		std  = msp_standard(state->norm);
		mode = msp_modus(client);
		std = (state->std & V4L2_STD_NTSC) ? 0x20 : 1;
		msp_write_dem(client, 0x30, mode);
		msp_write_dem(client, 0x20, std);
		state->watch_stereo = 0;
@@ -723,7 +721,7 @@ int msp3410d_thread(void *data)
		state->main   = msp_modelist[i].main;
		state->second = msp_modelist[i].second;

		if (amsound && (state->norm == VIDEO_MODE_SECAM) && (val != 0x0009)) {
		if (amsound && (state->std & V4L2_STD_SECAM) && (val != 0x0009)) {
			/* autodetection has failed, let backup */
			v4l_dbg(1, client, "autodetection failed,"
				" switching to backup mode: %s (0x%04x)\n",
@@ -772,7 +770,7 @@ int msp3410d_thread(void *data)
			state->audmode = V4L2_TUNER_MODE_STEREO;
			state->nicam_on = 0;
			state->watch_stereo = 0;
			/* not needed in theory if HAVE_RADIO(), but
			/* not needed in theory if we have radio, but
			   short programming enables carrier mute */
			msp3400c_setmode(client,MSP_MODE_FM_RADIO);
			msp3400c_setcarrier(client, MSP_CARRIER(10.7),
@@ -872,8 +870,11 @@ static int msp34xxg_reset(struct i2c_client *client)
	msp_write_dem(client, 0x40, state->i2s_mode);

	/* step-by-step initialisation, as described in the manual */
	modus = msp_modus(client, state->norm);
	std   = msp_standard(state->norm);
	modus = msp_modus(client);
	if (state->radio)
		std = 0x40;
	else
		std = (state->std & V4L2_STD_NTSC) ? 0x20 : 1;
	modus &= ~0x03; /* STATUS_CHANGE = 0 */
	modus |= 0x01;  /* AUTOMATIC_SOUND_DETECTION = 1 */
	if (msp_write_dem(client, 0x30, modus))
+14 −9
Original line number Diff line number Diff line
@@ -57,10 +57,21 @@ extern int stereo_threshold;

struct msp_state {
	int rev1, rev2;

	int has_nicam;
	int has_radio;
	int has_headphones;
	int has_ntsc_jp_d_k3;
	int has_scart4;
	int has_scart23_in_scart2_out;
	int has_subwoofer;
	int has_sound_processing;
	int has_virtual_dolby_surround;
	int has_dolby_pro_logic;

	int radio;
	int opmode;
	int mode;
	int norm;
	v4l2_std_id std;
	int stereo;
	int nicam_on;
	int acb;
@@ -85,11 +96,6 @@ struct msp_state {
	int                  watch_stereo:1;
};

#define VIDEO_MODE_RADIO 16      /* norm magic for radio mode */

#define HAVE_NICAM(state)   (((state->rev2 >> 8) & 0xff) != 0)
#define HAVE_RADIO(state)   ((state->rev1 & 0x0f) >= 'G'-'@')

/* msp3400-driver.c */
int msp_write_dem(struct i2c_client *client, int addr, int val);
int msp_write_dsp(struct i2c_client *client, int addr, int val);
@@ -99,8 +105,7 @@ int msp_reset(struct i2c_client *client);
void msp_set_scart(struct i2c_client *client, int in, int out);
void msp_set_mute(struct i2c_client *client);
void msp_set_audio(struct i2c_client *client);
int msp_modus(struct i2c_client *client, int norm);
int msp_standard(int norm);
int msp_modus(struct i2c_client *client);
int msp_sleep(struct msp_state *state, int timeout);

/* msp3400-kthreads.c */