saa7114.c

来自「trident tm5600的linux驱动」· C语言 代码 · 共 1,074 行 · 第 1/2 页

C
1,074
字号
		case VIDEO_MODE_PAL:			v4l_dbg(1, debug, client, "PAL\n");			decoder->reg[REG_ADDR(0x06)] =			    SAA_7114_PAL_HSYNC_START;			decoder->reg[REG_ADDR(0x07)] =			    SAA_7114_PAL_HSYNC_STOP;			decoder->reg[REG_ADDR(0x08)] = decoder->playback ? 0x7c : 0xb8;	// PLL free when playback, PLL close when capture			decoder->reg[REG_ADDR(0x0e)] = 0x81;			decoder->reg[REG_ADDR(0x0f)] = 0x24;			hoff = SAA_7114_PAL_HOFFSET;			voff = SAA_7114_PAL_VOFFSET;			w = SAA_7114_PAL_WIDTH;			h = SAA_7114_PAL_HEIGHT;			break;		default:			v4l_dbg(1, debug, client, "Unknown video mode\n");			return -EINVAL;		}		decoder->reg[REG_ADDR(0x94)] = LOBYTE(hoff);	// hoffset low		decoder->reg[REG_ADDR(0x95)] = HIBYTE(hoff) & 0x0f;	// hoffset high		decoder->reg[REG_ADDR(0x96)] = LOBYTE(w);	// width low		decoder->reg[REG_ADDR(0x97)] = HIBYTE(w) & 0x0f;	// width high		decoder->reg[REG_ADDR(0x98)] = LOBYTE(voff);	// voffset low		decoder->reg[REG_ADDR(0x99)] = HIBYTE(voff) & 0x0f;	// voffset high		decoder->reg[REG_ADDR(0x9a)] = LOBYTE(h + 2);	// height low		decoder->reg[REG_ADDR(0x9b)] = HIBYTE(h + 2) & 0x0f;	// height high		decoder->reg[REG_ADDR(0x9c)] = LOBYTE(w);	// out width low		decoder->reg[REG_ADDR(0x9d)] = HIBYTE(w) & 0x0f;	// out width high		decoder->reg[REG_ADDR(0x9e)] = LOBYTE(h);	// out height low		decoder->reg[REG_ADDR(0x9f)] = HIBYTE(h) & 0x0f;	// out height high		decoder->reg[REG_ADDR(0xc4)] = LOBYTE(hoff);	// hoffset low		decoder->reg[REG_ADDR(0xc5)] = HIBYTE(hoff) & 0x0f;	// hoffset high		decoder->reg[REG_ADDR(0xc6)] = LOBYTE(w);	// width low		decoder->reg[REG_ADDR(0xc7)] = HIBYTE(w) & 0x0f;	// width high		decoder->reg[REG_ADDR(0xc8)] = LOBYTE(voff);	// voffset low		decoder->reg[REG_ADDR(0xc9)] = HIBYTE(voff) & 0x0f;	// voffset high		decoder->reg[REG_ADDR(0xca)] = LOBYTE(h + 2);	// height low		decoder->reg[REG_ADDR(0xcb)] = HIBYTE(h + 2) & 0x0f;	// height high		decoder->reg[REG_ADDR(0xcc)] = LOBYTE(w);	// out width low		decoder->reg[REG_ADDR(0xcd)] = HIBYTE(w) & 0x0f;	// out width high		decoder->reg[REG_ADDR(0xce)] = LOBYTE(h);	// out height low		decoder->reg[REG_ADDR(0xcf)] = HIBYTE(h) & 0x0f;	// out height high		saa7114_write(client, 0x80, 0x06);	// i-port and scaler back end clock selection, task A&B off		saa7114_write(client, 0x88, 0xd8);	// sw reset scaler		saa7114_write(client, 0x88, 0xf8);	// sw reset scaler release		saa7114_write_block(client, decoder->reg + (0x06 << 1),				    3 << 1);		saa7114_write_block(client, decoder->reg + (0x0e << 1),				    2 << 1);		saa7114_write_block(client, decoder->reg + (0x5a << 1),				    2 << 1);		saa7114_write_block(client, decoder->reg + (0x94 << 1),				    (0x9f + 1 - 0x94) << 1);		saa7114_write_block(client, decoder->reg + (0xc4 << 1),				    (0xcf + 1 - 0xc4) << 1);		saa7114_write(client, 0x88, 0xd8);	// sw reset scaler		saa7114_write(client, 0x88, 0xf8);	// sw reset scaler release		saa7114_write(client, 0x80, 0x36);	// i-port and scaler back end clock selection		decoder->norm = *iarg;		break;	}	case DECODER_SET_INPUT:	{		int *iarg = arg;		v4l_dbg(1, debug, client, "set input (%d)\n", *iarg);		if (*iarg < 0 || *iarg > 7) {			return -EINVAL;		}		if (decoder->input != *iarg) {			v4l_dbg(1, debug, client, "now setting %s input\n",				*iarg >= 6 ? "S-Video" : "Composite");			decoder->input = *iarg;			/* select mode */			decoder->reg[REG_ADDR(0x02)] =			    (decoder->			     reg[REG_ADDR(0x02)] & 0xf0) | (decoder->							    input <							    6 ? 0x0 : 0x9);			saa7114_write(client, 0x02,				      decoder->reg[REG_ADDR(0x02)]);			/* bypass chrominance trap for modes 6..9 */			decoder->reg[REG_ADDR(0x09)] =			    (decoder->			     reg[REG_ADDR(0x09)] & 0x7f) | (decoder->							    input <							    6 ? 0x0 :							    0x80);			saa7114_write(client, 0x09,				      decoder->reg[REG_ADDR(0x09)]);			decoder->reg[REG_ADDR(0x0e)] =			    decoder->input <			    6 ? decoder->			    reg[REG_ADDR(0x0e)] | 1 : decoder->			    reg[REG_ADDR(0x0e)] & ~1;			saa7114_write(client, 0x0e,				      decoder->reg[REG_ADDR(0x0e)]);		}		break;	}	case DECODER_SET_OUTPUT:	{		int *iarg = arg;		v4l_dbg(1, debug, client, "set output\n");		/* not much choice of outputs */		if (*iarg != 0) {			return -EINVAL;		}		break;	}	case DECODER_ENABLE_OUTPUT:	{		int *iarg = arg;		int enable = (*iarg != 0);		v4l_dbg(1, debug, client, "%s output\n",			enable ? "enable" : "disable");		decoder->playback = !enable;		if (decoder->enable != enable) {			decoder->enable = enable;			/* RJ: If output should be disabled (for			 * playing videos), we also need a open PLL.			 * The input is set to 0 (where no input			 * source is connected), although this			 * is not necessary.			 *			 * If output should be enabled, we have to			 * reverse the above.			 */			if (decoder->enable) {				decoder->reg[REG_ADDR(0x08)] = 0xb8;				decoder->reg[REG_ADDR(0x12)] = 0xc9;				decoder->reg[REG_ADDR(0x13)] = 0x80;				decoder->reg[REG_ADDR(0x87)] = 0x01;			} else {				decoder->reg[REG_ADDR(0x08)] = 0x7c;				decoder->reg[REG_ADDR(0x12)] = 0x00;				decoder->reg[REG_ADDR(0x13)] = 0x00;				decoder->reg[REG_ADDR(0x87)] = 0x00;			}			saa7114_write_block(client,					    decoder->reg + (0x12 << 1),					    2 << 1);			saa7114_write(client, 0x08,				      decoder->reg[REG_ADDR(0x08)]);			saa7114_write(client, 0x87,				      decoder->reg[REG_ADDR(0x87)]);			saa7114_write(client, 0x88, 0xd8);	// sw reset scaler			saa7114_write(client, 0x88, 0xf8);	// sw reset scaler release			saa7114_write(client, 0x80, 0x36);		}		break;	}	case DECODER_SET_PICTURE:	{		struct video_picture *pic = arg;		v4l_dbg(1, debug, client,			"decoder set picture bright=%d contrast=%d saturation=%d hue=%d\n",			pic->brightness, pic->contrast, pic->colour, pic->hue);		if (decoder->bright != pic->brightness) {			/* We want 0 to 255 we get 0-65535 */			decoder->bright = pic->brightness;			saa7114_write(client, 0x0a, decoder->bright >> 8);		}		if (decoder->contrast != pic->contrast) {			/* We want 0 to 127 we get 0-65535 */			decoder->contrast = pic->contrast;			saa7114_write(client, 0x0b,				      decoder->contrast >> 9);		}		if (decoder->sat != pic->colour) {			/* We want 0 to 127 we get 0-65535 */			decoder->sat = pic->colour;			saa7114_write(client, 0x0c, decoder->sat >> 9);		}		if (decoder->hue != pic->hue) {			/* We want -128 to 127 we get 0-65535 */			decoder->hue = pic->hue;			saa7114_write(client, 0x0d,				      (decoder->hue - 32768) >> 8);		}		break;	}	default:		return -EINVAL;	}	return 0;}/* ----------------------------------------------------------------------- */static unsigned short normal_i2c[] = { 0x42 >> 1, 0x40 >> 1, I2C_CLIENT_END };I2C_CLIENT_INSMOD;static int saa7114_probe(struct i2c_client *client,			const struct i2c_device_id *id){	int i, err[30];	short int hoff = SAA_7114_NTSC_HOFFSET;	short int voff = SAA_7114_NTSC_VOFFSET;	short int w = SAA_7114_NTSC_WIDTH;	short int h = SAA_7114_NTSC_HEIGHT;	struct saa7114 *decoder;	/* Check if the adapter supports the needed features */	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))		return -ENODEV;	v4l_info(client, "chip found @ 0x%x (%s)\n",			client->addr << 1, client->adapter->name);	decoder = kzalloc(sizeof(struct saa7114), GFP_KERNEL);	if (decoder == NULL)		return -ENOMEM;	decoder->norm = VIDEO_MODE_NTSC;	decoder->input = -1;	decoder->enable = 1;	decoder->bright = 32768;	decoder->contrast = 32768;	decoder->hue = 32768;	decoder->sat = 32768;	decoder->playback = 0;	// initially capture mode useda	i2c_set_clientdata(client, decoder);	memcpy(decoder->reg, init, sizeof(init));	decoder->reg[REG_ADDR(0x94)] = LOBYTE(hoff);	// hoffset low	decoder->reg[REG_ADDR(0x95)] = HIBYTE(hoff) & 0x0f;	// hoffset high	decoder->reg[REG_ADDR(0x96)] = LOBYTE(w);	// width low	decoder->reg[REG_ADDR(0x97)] = HIBYTE(w) & 0x0f;	// width high	decoder->reg[REG_ADDR(0x98)] = LOBYTE(voff);	// voffset low	decoder->reg[REG_ADDR(0x99)] = HIBYTE(voff) & 0x0f;	// voffset high	decoder->reg[REG_ADDR(0x9a)] = LOBYTE(h + 2);	// height low	decoder->reg[REG_ADDR(0x9b)] = HIBYTE(h + 2) & 0x0f;	// height high	decoder->reg[REG_ADDR(0x9c)] = LOBYTE(w);	// out width low	decoder->reg[REG_ADDR(0x9d)] = HIBYTE(w) & 0x0f;	// out width high	decoder->reg[REG_ADDR(0x9e)] = LOBYTE(h);	// out height low	decoder->reg[REG_ADDR(0x9f)] = HIBYTE(h) & 0x0f;	// out height high	decoder->reg[REG_ADDR(0xc4)] = LOBYTE(hoff);	// hoffset low	decoder->reg[REG_ADDR(0xc5)] = HIBYTE(hoff) & 0x0f;	// hoffset high	decoder->reg[REG_ADDR(0xc6)] = LOBYTE(w);	// width low	decoder->reg[REG_ADDR(0xc7)] = HIBYTE(w) & 0x0f;	// width high	decoder->reg[REG_ADDR(0xc8)] = LOBYTE(voff);	// voffset low	decoder->reg[REG_ADDR(0xc9)] = HIBYTE(voff) & 0x0f;	// voffset high	decoder->reg[REG_ADDR(0xca)] = LOBYTE(h + 2);	// height low	decoder->reg[REG_ADDR(0xcb)] = HIBYTE(h + 2) & 0x0f;	// height high	decoder->reg[REG_ADDR(0xcc)] = LOBYTE(w);	// out width low	decoder->reg[REG_ADDR(0xcd)] = HIBYTE(w) & 0x0f;	// out width high	decoder->reg[REG_ADDR(0xce)] = LOBYTE(h);	// out height low	decoder->reg[REG_ADDR(0xcf)] = HIBYTE(h) & 0x0f;	// out height high	decoder->reg[REG_ADDR(0xb8)] =	    LOBYTE(LOWORD(SAA_7114_VERTICAL_CHROMA_OFFSET));	decoder->reg[REG_ADDR(0xb9)] =	    HIBYTE(LOWORD(SAA_7114_VERTICAL_CHROMA_OFFSET));	decoder->reg[REG_ADDR(0xba)] =	    LOBYTE(HIWORD(SAA_7114_VERTICAL_CHROMA_OFFSET));	decoder->reg[REG_ADDR(0xbb)] =	    HIBYTE(HIWORD(SAA_7114_VERTICAL_CHROMA_OFFSET));	decoder->reg[REG_ADDR(0xbc)] =	    LOBYTE(LOWORD(SAA_7114_VERTICAL_LUMA_OFFSET));	decoder->reg[REG_ADDR(0xbd)] =	    HIBYTE(LOWORD(SAA_7114_VERTICAL_LUMA_OFFSET));	decoder->reg[REG_ADDR(0xbe)] =	    LOBYTE(HIWORD(SAA_7114_VERTICAL_LUMA_OFFSET));	decoder->reg[REG_ADDR(0xbf)] =	    HIBYTE(HIWORD(SAA_7114_VERTICAL_LUMA_OFFSET));	decoder->reg[REG_ADDR(0xe8)] =	    LOBYTE(LOWORD(SAA_7114_VERTICAL_CHROMA_OFFSET));	decoder->reg[REG_ADDR(0xe9)] =	    HIBYTE(LOWORD(SAA_7114_VERTICAL_CHROMA_OFFSET));	decoder->reg[REG_ADDR(0xea)] =	    LOBYTE(HIWORD(SAA_7114_VERTICAL_CHROMA_OFFSET));	decoder->reg[REG_ADDR(0xeb)] =	    HIBYTE(HIWORD(SAA_7114_VERTICAL_CHROMA_OFFSET));	decoder->reg[REG_ADDR(0xec)] =	    LOBYTE(LOWORD(SAA_7114_VERTICAL_LUMA_OFFSET));	decoder->reg[REG_ADDR(0xed)] =	    HIBYTE(LOWORD(SAA_7114_VERTICAL_LUMA_OFFSET));	decoder->reg[REG_ADDR(0xee)] =	    LOBYTE(HIWORD(SAA_7114_VERTICAL_LUMA_OFFSET));	decoder->reg[REG_ADDR(0xef)] =	    HIBYTE(HIWORD(SAA_7114_VERTICAL_LUMA_OFFSET));	decoder->reg[REG_ADDR(0x13)] = 0x80;	// RTC0 on	decoder->reg[REG_ADDR(0x87)] = 0x01;	// I-Port	decoder->reg[REG_ADDR(0x12)] = 0xc9;	// RTS0	decoder->reg[REG_ADDR(0x02)] = 0xc0;	// set composite1 input, aveasy	decoder->reg[REG_ADDR(0x09)] = 0x00;	// chrominance trap	decoder->reg[REG_ADDR(0x0e)] |= 1;	// combfilter on	v4l_dbg(1, debug, client, "starting init\n");	err[0] =	    saa7114_write_block(client, decoder->reg + (0x20 << 1),				0x10 << 1);	err[1] =	    saa7114_write_block(client, decoder->reg + (0x30 << 1),				0x10 << 1);	err[2] =	    saa7114_write_block(client, decoder->reg + (0x63 << 1),				(0x7f + 1 - 0x63) << 1);	err[3] =	    saa7114_write_block(client, decoder->reg + (0x89 << 1),				6 << 1);	err[4] =	    saa7114_write_block(client, decoder->reg + (0xb8 << 1),				8 << 1);	err[5] =	    saa7114_write_block(client, decoder->reg + (0xe8 << 1),				8 << 1);	for (i = 0; i <= 5; i++) {		if (err[i] < 0) {			v4l_dbg(1, debug, client,				"init error %d at stage %d, leaving attach.\n",				i, err[i]);			kfree(decoder);			return -EIO;		}	}	for (i = 6; i < 8; i++) {		v4l_dbg(1, debug, client,			"reg[0x%02x] = 0x%02x (0x%02x)\n",			i, saa7114_read(client, i),			decoder->reg[REG_ADDR(i)]);	}	v4l_dbg(1, debug, client,		"performing decoder reset sequence\n");	err[6] = saa7114_write(client, 0x80, 0x06);	// i-port and scaler backend clock selection, task A&B off	err[7] = saa7114_write(client, 0x88, 0xd8);	// sw reset scaler	err[8] = saa7114_write(client, 0x88, 0xf8);	// sw reset scaler release	for (i = 6; i <= 8; i++) {		if (err[i] < 0) {			v4l_dbg(1, debug, client,				"init error %d at stage %d, leaving attach.\n",				i, err[i]);			kfree(decoder);			return -EIO;		}	}	v4l_dbg(1, debug, client, "performing the rest of init\n");	err[9] = saa7114_write(client, 0x01, decoder->reg[REG_ADDR(0x01)]);	err[10] = saa7114_write_block(client, decoder->reg + (0x03 << 1), (0x1e + 1 - 0x03) << 1);	// big seq	err[11] = saa7114_write_block(client, decoder->reg + (0x40 << 1), (0x5f + 1 - 0x40) << 1);	// slicer	err[12] = saa7114_write_block(client, decoder->reg + (0x81 << 1), 2 << 1);	// ?	err[13] = saa7114_write_block(client, decoder->reg + (0x83 << 1), 5 << 1);	// ?	err[14] = saa7114_write_block(client, decoder->reg + (0x90 << 1), 4 << 1);	// Task A	err[15] =	    saa7114_write_block(client, decoder->reg + (0x94 << 1),				12 << 1);	err[16] =	    saa7114_write_block(client, decoder->reg + (0xa0 << 1),				8 << 1);	err[17] =	    saa7114_write_block(client, decoder->reg + (0xa8 << 1),				8 << 1);	err[18] =	    saa7114_write_block(client, decoder->reg + (0xb0 << 1),				8 << 1);	err[19] = saa7114_write_block(client, decoder->reg + (0xc0 << 1), 4 << 1);	// Task B	err[15] =	    saa7114_write_block(client, decoder->reg + (0xc4 << 1),				12 << 1);	err[16] =	    saa7114_write_block(client, decoder->reg + (0xd0 << 1),				8 << 1);	err[17] =	    saa7114_write_block(client, decoder->reg + (0xd8 << 1),				8 << 1);	err[18] =	    saa7114_write_block(client, decoder->reg + (0xe0 << 1),				8 << 1);	for (i = 9; i <= 18; i++) {		if (err[i] < 0) {			v4l_dbg(1, debug, client,				"init error %d at stage %d, leaving attach.\n",				i, err[i]);			kfree(decoder);			return -EIO;		}	}	for (i = 6; i < 8; i++) {		v4l_dbg(1, debug, client,			"reg[0x%02x] = 0x%02x (0x%02x)\n",			i, saa7114_read(client, i),			decoder->reg[REG_ADDR(i)]);	}	for (i = 0x11; i <= 0x13; i++) {		v4l_dbg(1, debug, client,			"reg[0x%02x] = 0x%02x (0x%02x)\n",			i, saa7114_read(client, i),			decoder->reg[REG_ADDR(i)]);	}	v4l_dbg(1, debug, client, "setting video input\n");	err[19] =	    saa7114_write(client, 0x02, decoder->reg[REG_ADDR(0x02)]);	err[20] =	    saa7114_write(client, 0x09, decoder->reg[REG_ADDR(0x09)]);	err[21] =	    saa7114_write(client, 0x0e, decoder->reg[REG_ADDR(0x0e)]);	for (i = 19; i <= 21; i++) {		if (err[i] < 0) {			v4l_dbg(1, debug, client,				"init error %d at stage %d, leaving attach.\n",				i, err[i]);			kfree(decoder);			return -EIO;		}	}	v4l_dbg(1, debug, client, "performing decoder reset sequence\n");	err[22] = saa7114_write(client, 0x88, 0xd8);	// sw reset scaler	err[23] = saa7114_write(client, 0x88, 0xf8);	// sw reset scaler release	err[24] = saa7114_write(client, 0x80, 0x36);	// i-port and scaler backend clock selection, task A&B off	for (i = 22; i <= 24; i++) {		if (err[i] < 0) {			v4l_dbg(1, debug, client,				"init error %d at stage %d, leaving attach.\n",				i, err[i]);			kfree(decoder);			return -EIO;		}	}	err[25] = saa7114_write(client, 0x06, init[REG_ADDR(0x06)]);	err[26] = saa7114_write(client, 0x07, init[REG_ADDR(0x07)]);	err[27] = saa7114_write(client, 0x10, init[REG_ADDR(0x10)]);	v4l_dbg(1, debug, client, "chip version %x, decoder status 0x%02x\n",		saa7114_read(client, 0x00) >> 4,		saa7114_read(client, 0x1f));	v4l_dbg(1, debug, client,		"power save control: 0x%02x, scaler status: 0x%02x\n",		saa7114_read(client, 0x88),		saa7114_read(client, 0x8f));	for (i = 0x94; i < 0x96; i++) {		v4l_dbg(1, debug, client,			"reg[0x%02x] = 0x%02x (0x%02x)\n",			i, saa7114_read(client, i),			decoder->reg[REG_ADDR(i)]);	}	//i = saa7114_write_block(client, init, sizeof(init));	return 0;}static int saa7114_remove(struct i2c_client *client){	kfree(i2c_get_clientdata(client));	return 0;}/* ----------------------------------------------------------------------- */#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)static const struct i2c_device_id saa7114_id[] = {	{ "saa7114_old", 0 },	/* "saa7114" maps to the saa7115 driver */	{ }};MODULE_DEVICE_TABLE(i2c, saa7114_id);#endifstatic struct v4l2_i2c_driver_data v4l2_i2c_data = {	.name = "saa7114",	.driverid = I2C_DRIVERID_SAA7114,	.command = saa7114_command,	.probe = saa7114_probe,	.remove = saa7114_remove,#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)	.id_table = saa7114_id,#endif};

⌨️ 快捷键说明

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