⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cx25840-core.c

📁 trident tm5600的linux驱动
💻 C
📖 第 1 页 / 共 3 页
字号:
	/* Sets Luma and UV Low pass filters */	cx25840_write(client, 0x47a, luma_lpf << 6 | ((uv_lpf << 4) & 0x30));	/* Enables comb filters */	cx25840_write(client, 0x47b, comb);	/* Sets SC Step*/	cx25840_write(client, 0x47c, sc);	cx25840_write(client, 0x47d, 0xff & sc >> 8);	cx25840_write(client, 0x47e, 0xff & sc >> 16);	/* Sets VBI parameters */	if (std & V4L2_STD_625_50) {		cx25840_write(client, 0x47f, 0x01);		state->vbi_line_offset = 5;	} else {		cx25840_write(client, 0x47f, 0x00);		state->vbi_line_offset = 8;	}}/* ----------------------------------------------------------------------- */static void input_change(struct i2c_client *client){	struct cx25840_state *state = i2c_get_clientdata(client);	v4l2_std_id std = state->std;	/* Follow step 8c and 8d of section 3.16 in the cx25840 datasheet */	if (std & V4L2_STD_SECAM) {		cx25840_write(client, 0x402, 0);	}	else {		cx25840_write(client, 0x402, 0x04);		cx25840_write(client, 0x49f, (std & V4L2_STD_NTSC) ? 0x14 : 0x11);	}	cx25840_and_or(client, 0x401, ~0x60, 0);	cx25840_and_or(client, 0x401, ~0x60, 0x60);	cx25840_and_or(client, 0x810, ~0x01, 1);	if (state->radio) {		cx25840_write(client, 0x808, 0xf9);		cx25840_write(client, 0x80b, 0x00);	}	else if (std & V4L2_STD_525_60) {		/* Certain Hauppauge PVR150 models have a hardware bug		   that causes audio to drop out. For these models the		   audio standard must be set explicitly.		   To be precise: it affects cards with tuner models		   85, 99 and 112 (model numbers from tveeprom). */		int hw_fix = state->pvr150_workaround;		if (std == V4L2_STD_NTSC_M_JP) {			/* Japan uses EIAJ audio standard */			cx25840_write(client, 0x808, hw_fix ? 0x2f : 0xf7);		} else if (std == V4L2_STD_NTSC_M_KR) {			/* South Korea uses A2 audio standard */			cx25840_write(client, 0x808, hw_fix ? 0x3f : 0xf8);		} else {			/* Others use the BTSC audio standard */			cx25840_write(client, 0x808, hw_fix ? 0x1f : 0xf6);		}		cx25840_write(client, 0x80b, 0x00);	} else if (std & V4L2_STD_PAL) {		/* Follow tuner change procedure for PAL */		cx25840_write(client, 0x808, 0xff);		cx25840_write(client, 0x80b, 0x10);	} else if (std & V4L2_STD_SECAM) {		/* Select autodetect for SECAM */		cx25840_write(client, 0x808, 0xff);		cx25840_write(client, 0x80b, 0x10);	}	cx25840_and_or(client, 0x810, ~0x01, 0);}static int set_input(struct i2c_client *client, enum cx25840_video_input vid_input,						enum cx25840_audio_input aud_input){	struct cx25840_state *state = i2c_get_clientdata(client);	u8 is_composite = (vid_input >= CX25840_COMPOSITE1 &&			   vid_input <= CX25840_COMPOSITE8);	u8 reg;	v4l_dbg(1, cx25840_debug, client,		"decoder set video input %d, audio input %d\n",		vid_input, aud_input);	if (vid_input >= CX25840_VIN1_CH1) {		v4l_dbg(1, cx25840_debug, client, "vid_input 0x%x\n",			vid_input);		reg = vid_input & 0xff;		if ((vid_input & CX25840_SVIDEO_ON) == CX25840_SVIDEO_ON)			is_composite = 0;		else			is_composite = 1;		v4l_dbg(1, cx25840_debug, client, "mux cfg 0x%x comp=%d\n",			reg, is_composite);	} else	if (is_composite) {		reg = 0xf0 + (vid_input - CX25840_COMPOSITE1);	} else {		int luma = vid_input & 0xf0;		int chroma = vid_input & 0xf00;		if ((vid_input & ~0xff0) ||		    luma < CX25840_SVIDEO_LUMA1 || luma > CX25840_SVIDEO_LUMA8 ||		    chroma < CX25840_SVIDEO_CHROMA4 || chroma > CX25840_SVIDEO_CHROMA8) {			v4l_err(client, "0x%04x is not a valid video input!\n",				vid_input);			return -EINVAL;		}		reg = 0xf0 + ((luma - CX25840_SVIDEO_LUMA1) >> 4);		if (chroma >= CX25840_SVIDEO_CHROMA7) {			reg &= 0x3f;			reg |= (chroma - CX25840_SVIDEO_CHROMA7) >> 2;		} else {			reg &= 0xcf;			reg |= (chroma - CX25840_SVIDEO_CHROMA4) >> 4;		}	}	/* The caller has previously prepared the correct routing	 * configuration in reg (for the cx23885) so we have no	 * need to attempt to flip bits for earlier av decoders.	 */	if (!state->is_cx23885) {		switch (aud_input) {		case CX25840_AUDIO_SERIAL:			/* do nothing, use serial audio input */			break;		case CX25840_AUDIO4: reg &= ~0x30; break;		case CX25840_AUDIO5: reg &= ~0x30; reg |= 0x10; break;		case CX25840_AUDIO6: reg &= ~0x30; reg |= 0x20; break;		case CX25840_AUDIO7: reg &= ~0xc0; break;		case CX25840_AUDIO8: reg &= ~0xc0; reg |= 0x40; break;		default:			v4l_err(client, "0x%04x is not a valid audio input!\n",				aud_input);			return -EINVAL;		}	}	cx25840_write(client, 0x103, reg);	/* Set INPUT_MODE to Composite (0) or S-Video (1) */	cx25840_and_or(client, 0x401, ~0x6, is_composite ? 0 : 0x02);	if (!state->is_cx23885) {		/* Set CH_SEL_ADC2 to 1 if input comes from CH3 */		cx25840_and_or(client, 0x102, ~0x2, (reg & 0x80) == 0 ? 2 : 0);		/* Set DUAL_MODE_ADC2 to 1 if input comes from both CH2&CH3 */		if ((reg & 0xc0) != 0xc0 && (reg & 0x30) != 0x30)			cx25840_and_or(client, 0x102, ~0x4, 4);		else			cx25840_and_or(client, 0x102, ~0x4, 0);	} else {		if (is_composite)			/* ADC2 input select channel 2 */			cx25840_and_or(client, 0x102, ~0x2, 0);		else			/* ADC2 input select channel 3 */			cx25840_and_or(client, 0x102, ~0x2, 2);	}	state->vid_input = vid_input;	state->aud_input = aud_input;	if (!state->is_cx25836) {		cx25840_audio_set_path(client);		input_change(client);	}	if (state->is_cx23885) {		/* Audio channel 1 src : Parallel 1 */		cx25840_write(client, 0x124, 0x03);		/* Select AFE clock pad output source */		cx25840_write(client, 0x144, 0x05);		/* I2S_IN_CTL: I2S_IN_SONY_MODE, LEFT SAMPLE on WS=1 */		cx25840_write(client, 0x914, 0xa0);		/* I2S_OUT_CTL:		 * I2S_IN_SONY_MODE, LEFT SAMPLE on WS=1		 * I2S_OUT_MASTER_MODE = Master		 */		cx25840_write(client, 0x918, 0xa0);		cx25840_write(client, 0x919, 0x01);	}	return 0;}/* ----------------------------------------------------------------------- */static int set_v4lstd(struct i2c_client *client){	struct cx25840_state *state = i2c_get_clientdata(client);	u8 fmt = 0; 	/* zero is autodetect */	u8 pal_m = 0;	/* First tests should be against specific std */	if (state->std == V4L2_STD_NTSC_M_JP) {		fmt = 0x2;	} else if (state->std == V4L2_STD_NTSC_443) {		fmt = 0x3;	} else if (state->std == V4L2_STD_PAL_M) {		pal_m = 1;		fmt = 0x5;	} else if (state->std == V4L2_STD_PAL_N) {		fmt = 0x6;	} else if (state->std == V4L2_STD_PAL_Nc) {		fmt = 0x7;	} else if (state->std == V4L2_STD_PAL_60) {		fmt = 0x8;	} else {		/* Then, test against generic ones */		if (state->std & V4L2_STD_NTSC)			fmt = 0x1;		else if (state->std & V4L2_STD_PAL)			fmt = 0x4;		else if (state->std & V4L2_STD_SECAM)			fmt = 0xc;	}	v4l_dbg(1, cx25840_debug, client, "changing video std to fmt %i\n",fmt);	/* Follow step 9 of section 3.16 in the cx25840 datasheet.	   Without this PAL may display a vertical ghosting effect.	   This happens for example with the Yuan MPC622. */	if (fmt >= 4 && fmt < 8) {		/* Set format to NTSC-M */		cx25840_and_or(client, 0x400, ~0xf, 1);		/* Turn off LCOMB */		cx25840_and_or(client, 0x47b, ~6, 0);	}	cx25840_and_or(client, 0x400, ~0xf, fmt);	cx25840_and_or(client, 0x403, ~0x3, pal_m);	cx25840_std_setup(client);	if (!state->is_cx25836)		input_change(client);	return 0;}/* ----------------------------------------------------------------------- */static int set_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl){	struct cx25840_state *state = i2c_get_clientdata(client);	switch (ctrl->id) {	case CX25840_CID_ENABLE_PVR150_WORKAROUND:		state->pvr150_workaround = ctrl->value;		set_input(client, state->vid_input, state->aud_input);		break;	case V4L2_CID_BRIGHTNESS:		if (ctrl->value < 0 || ctrl->value > 255) {			v4l_err(client, "invalid brightness setting %d\n",				    ctrl->value);			return -ERANGE;		}		cx25840_write(client, 0x414, ctrl->value - 128);		break;	case V4L2_CID_CONTRAST:		if (ctrl->value < 0 || ctrl->value > 127) {			v4l_err(client, "invalid contrast setting %d\n",				    ctrl->value);			return -ERANGE;		}		cx25840_write(client, 0x415, ctrl->value << 1);		break;	case V4L2_CID_SATURATION:		if (ctrl->value < 0 || ctrl->value > 127) {			v4l_err(client, "invalid saturation setting %d\n",				    ctrl->value);			return -ERANGE;		}		cx25840_write(client, 0x420, ctrl->value << 1);		cx25840_write(client, 0x421, ctrl->value << 1);		break;	case V4L2_CID_HUE:		if (ctrl->value < -127 || ctrl->value > 127) {			v4l_err(client, "invalid hue setting %d\n", ctrl->value);			return -ERANGE;		}		cx25840_write(client, 0x422, ctrl->value);		break;	case V4L2_CID_AUDIO_VOLUME:	case V4L2_CID_AUDIO_BASS:	case V4L2_CID_AUDIO_TREBLE:	case V4L2_CID_AUDIO_BALANCE:	case V4L2_CID_AUDIO_MUTE:		if (state->is_cx25836)			return -EINVAL;		return cx25840_audio(client, VIDIOC_S_CTRL, ctrl);	default:		return -EINVAL;	}	return 0;}static int get_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl){	struct cx25840_state *state = i2c_get_clientdata(client);	switch (ctrl->id) {	case CX25840_CID_ENABLE_PVR150_WORKAROUND:		ctrl->value = state->pvr150_workaround;		break;	case V4L2_CID_BRIGHTNESS:		ctrl->value = (s8)cx25840_read(client, 0x414) + 128;		break;	case V4L2_CID_CONTRAST:		ctrl->value = cx25840_read(client, 0x415) >> 1;		break;	case V4L2_CID_SATURATION:		ctrl->value = cx25840_read(client, 0x420) >> 1;		break;	case V4L2_CID_HUE:		ctrl->value = (s8)cx25840_read(client, 0x422);		break;	case V4L2_CID_AUDIO_VOLUME:	case V4L2_CID_AUDIO_BASS:	case V4L2_CID_AUDIO_TREBLE:	case V4L2_CID_AUDIO_BALANCE:	case V4L2_CID_AUDIO_MUTE:		if (state->is_cx25836)			return -EINVAL;		return cx25840_audio(client, VIDIOC_G_CTRL, ctrl);	default:		return -EINVAL;	}	return 0;}/* ----------------------------------------------------------------------- */static int get_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt){	switch (fmt->type) {	case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:		return cx25840_vbi(client, VIDIOC_G_FMT, fmt);	default:		return -EINVAL;	}	return 0;}static int set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt){	struct cx25840_state *state = i2c_get_clientdata(client);	struct v4l2_pix_format *pix;	int HSC, VSC, Vsrc, Hsrc, filter, Vlines;	int is_50Hz = !(state->std & V4L2_STD_525_60);	switch (fmt->type) {	case V4L2_BUF_TYPE_VIDEO_CAPTURE:		pix = &(fmt->fmt.pix);		Vsrc = (cx25840_read(client, 0x476) & 0x3f) << 4;		Vsrc |= (cx25840_read(client, 0x475) & 0xf0) >> 4;		Hsrc = (cx25840_read(client, 0x472) & 0x3f) << 4;		Hsrc |= (cx25840_read(client, 0x471) & 0xf0) >> 4;		Vlines = pix->height + (is_50Hz ? 4 : 7);		if ((pix->width * 16 < Hsrc) || (Hsrc < pix->width) ||		    (Vlines * 8 < Vsrc) || (Vsrc < Vlines)) {			v4l_err(client, "%dx%d is not a valid size!\n",				    pix->width, pix->height);			return -ERANGE;		}		HSC = (Hsrc * (1 << 20)) / pix->width - (1 << 20);		VSC = (1 << 16) - (Vsrc * (1 << 9) / Vlines - (1 << 9));		VSC &= 0x1fff;		if (pix->width >= 385)			filter = 0;		else if (pix->width > 192)			filter = 1;		else if (pix->width > 96)			filter = 2;		else			filter = 3;		v4l_dbg(1, cx25840_debug, client, "decoder set size %dx%d -> scale  %ux%u\n",			    pix->width, pix->height, HSC, VSC);		/* HSCALE=HSC */		cx25840_write(client, 0x418, HSC & 0xff);		cx25840_write(client, 0x419, (HSC >> 8) & 0xff);		cx25840_write(client, 0x41a, HSC >> 16);		/* VSCALE=VSC */		cx25840_write(client, 0x41c, VSC & 0xff);		cx25840_write(client, 0x41d, VSC >> 8);		/* VS_INTRLACE=1 VFILT=filter */		cx25840_write(client, 0x41e, 0x8 | filter);		break;	case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:		return cx25840_vbi(client, VIDIOC_S_FMT, fmt);	case V4L2_BUF_TYPE_VBI_CAPTURE:		return cx25840_vbi(client, VIDIOC_S_FMT, fmt);	default:		return -EINVAL;	}	return 0;}/* ----------------------------------------------------------------------- */static void log_video_status(struct i2c_client *client){	static const char *const fmt_strs[] = {		"0x0",		"NTSC-M", "NTSC-J", "NTSC-4.43",		"PAL-BDGHI", "PAL-M", "PAL-N", "PAL-Nc", "PAL-60",		"0x9", "0xA", "0xB",		"SECAM",		"0xD", "0xE", "0xF"	};	struct cx25840_state *state = i2c_get_clientdata(client);	u8 vidfmt_sel = cx25840_read(client, 0x400) & 0xf;	u8 gen_stat1 = cx25840_read(client, 0x40d);	u8 gen_stat2 = cx25840_read(client, 0x40e);	int vid_input = state->vid_input;	v4l_info(client, "Video signal:              %spresent\n",		    (gen_stat2 & 0x20) ? "" : "not ");	v4l_info(client, "Detected format:           %s\n",		    fmt_strs[gen_stat1 & 0xf]);	v4l_info(client, "Specified standard:        %s\n",		    vidfmt_sel ? fmt_strs[vidfmt_sel] : "automatic detection");	if (vid_input >= CX25840_COMPOSITE1 &&	    vid_input <= CX25840_COMPOSITE8) {		v4l_info(client, "Specified video input:     Composite %d\n",			vid_input - CX25840_COMPOSITE1 + 1);	} else {		v4l_info(client, "Specified video input:     S-Video (Luma In%d, Chroma In%d)\n",			(vid_input & 0xf0) >> 4, (vid_input & 0xf00) >> 8);	}	v4l_info(client, "Specified audioclock freq: %d Hz\n", state->audclk_freq);}/* ----------------------------------------------------------------------- */static void log_audio_status(struct i2c_client *client){	struct cx25840_state *state = i2c_get_clientdata(client);	u8 download_ctl = cx25840_read(client, 0x803);	u8 mod_det_stat0 = cx25840_read(client, 0x804);	u8 mod_det_stat1 = cx25840_read(client, 0x805);	u8 audio_config = cx25840_read(client, 0x808);	u8 pref_mode = cx25840_read(client, 0x809);	u8 afc0 = cx25840_read(client, 0x80b);	u8 mute_ctl = cx25840_read(client, 0x8d3);	int aud_input = state->aud_input;	char *p;	switch (mod_det_stat0) {	case 0x00: p = "mono"; break;	case 0x01: p = "stereo"; break;	case 0x02: p = "dual"; break;	case 0x04: p = "tri"; break;	case 0x10: p = "mono with SAP"; break;	case 0x11: p = "stereo with SAP"; break;	case 0x12: p = "dual with SAP"; break;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -