static int
saa7114_write_block (struct i2c_client *client,
		     const u8          *data,
		     unsigned int       len)
{
	int ret = -1;
	u8 reg;

	/* the saa7114 has an autoincrement function, use it if
	 * the adapter understands raw I2C */
	if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
		/* do raw I2C, not smbus compatible */
		/*struct saa7114 *decoder = i2c_get_clientdata(client);*/
		struct i2c_msg msg;
		u8 block_data[32];

		msg.addr = client->addr;
		msg.flags = client->flags;
		while (len >= 2) {
			msg.buf = (char *) block_data;
			msg.len = 0;
			block_data[msg.len++] = reg = data[0];
			do {
				block_data[msg.len++] =
				    /*decoder->reg[reg++] =*/ data[1];
				len -= 2;
				data += 2;
			} while (len >= 2 && data[0] == reg &&
				 msg.len < 32);
			if ((ret = i2c_transfer(client->adapter,
						&msg, 1)) < 0)
				break;
		}
	} else {
		/* do some slow I2C emulation kind of thing */
		while (len >= 2) {
			reg = *data++;
			if ((ret = saa7114_write(client, reg,
						 *data++)) < 0)
				break;
			len -= 2;
		}
	}

	return ret;
}
Exemplo n.º 2
0
static int
saa7114_write_block (struct i2c_client *client,
		     const u8          *data,
		     unsigned int       len)
{
	int ret = -1;
	u8 reg;

	/* the saa7114 has an autoincrement function, use it if
	 * the adapter understands raw I2C */
	if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
		/* do raw I2C, not smbus compatible */
		u8 block_data[32];
		int block_len;

		while (len >= 2) {
			block_len = 0;
			block_data[block_len++] = reg = data[0];
			do {
				block_data[block_len++] = data[1];
				reg++;
				len -= 2;
				data += 2;
			} while (len >= 2 && data[0] == reg &&
				 block_len < 32);
			if ((ret = i2c_master_send(client, block_data,
						   block_len)) < 0)
				break;
		}
	} else {
		/* do some slow I2C emulation kind of thing */
		while (len >= 2) {
			reg = *data++;
			if ((ret = saa7114_write(client, reg,
						 *data++)) < 0)
				break;
			len -= 2;
		}
	}

	return ret;
}
static int
saa7114_command (struct i2c_client *client,
		 unsigned int       cmd,
		 void              *arg)
{
	struct saa7114 *decoder = i2c_get_clientdata(client);

	switch (cmd) {

	case 0:
		//dprintk(1, KERN_INFO "%s: writing init\n", I2C_NAME(client));
		//saa7114_write_block(client, init, sizeof(init));
		break;

	case DECODER_DUMP:
	{
		int i;

		dprintk(1, KERN_INFO "%s: decoder dump\n", I2C_NAME(client));

		for (i = 0; i < 32; i += 16) {
			int j;

			printk(KERN_DEBUG "%s: %03x", I2C_NAME(client), i);
			for (j = 0; j < 16; ++j) {
				printk(" %02x",
				       saa7114_read(client, i + j));
			}
			printk("\n");
		}
	}
		break;

	case DECODER_GET_CAPABILITIES:
	{
		struct video_decoder_capability *cap = arg;

		dprintk(1, KERN_DEBUG "%s: decoder get capabilities\n",
			I2C_NAME(client));

		cap->flags = VIDEO_DECODER_PAL |
			     VIDEO_DECODER_NTSC |
			     VIDEO_DECODER_AUTO |
			     VIDEO_DECODER_CCIR;
		cap->inputs = 8;
		cap->outputs = 1;
	}
		break;

	case DECODER_GET_STATUS:
	{
		int *iarg = arg;
		int status;
		int res;

		status = saa7114_read(client, 0x1f);

		dprintk(1, KERN_DEBUG "%s status: 0x%02x\n", I2C_NAME(client),
			status);
		res = 0;
		if ((status & (1 << 6)) == 0) {
			res |= DECODER_STATUS_GOOD;
		}
		switch (decoder->norm) {
		case VIDEO_MODE_NTSC:
			res |= DECODER_STATUS_NTSC;
			break;
		case VIDEO_MODE_PAL:
			res |= DECODER_STATUS_PAL;
			break;
		case VIDEO_MODE_SECAM:
			res |= DECODER_STATUS_SECAM;
			break;
		default:
		case VIDEO_MODE_AUTO:
			if ((status & (1 << 5)) != 0) {
				res |= DECODER_STATUS_NTSC;
			} else {
				res |= DECODER_STATUS_PAL;
			}
			break;
		}
		if ((status & (1 << 0)) != 0) {
			res |= DECODER_STATUS_COLOR;
		}
		*iarg = res;
	}
		break;

	case DECODER_SET_NORM:
	{
		int *iarg = arg;

		short int hoff = 0, voff = 0, w = 0, h = 0;

		dprintk(1, KERN_DEBUG "%s: decoder set norm ",
			I2C_NAME(client));
		switch (*iarg) {

		case VIDEO_MODE_NTSC:
			dprintk(1, "NTSC\n");
			decoder->reg[REG_ADDR(0x06)] =
			    SAA_7114_NTSC_HSYNC_START;
			decoder->reg[REG_ADDR(0x07)] =
			    SAA_7114_NTSC_HSYNC_STOP;

			decoder->reg[REG_ADDR(0x08)] = decoder->playback ? 0x7c : 0xb8;	// PLL free when playback, PLL close when capture

			decoder->reg[REG_ADDR(0x0e)] = 0x85;
			decoder->reg[REG_ADDR(0x0f)] = 0x24;

			hoff = SAA_7114_NTSC_HOFFSET;
			voff = SAA_7114_NTSC_VOFFSET;
			w = SAA_7114_NTSC_WIDTH;
			h = SAA_7114_NTSC_HEIGHT;

			break;

		case VIDEO_MODE_PAL:
			dprintk(1, "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:
			dprintk(1, " 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;

		dprintk(1, KERN_DEBUG "%s: decoder set input (%d)\n",
			I2C_NAME(client), *iarg);
		if (*iarg < 0 || *iarg > 7) {
			return -EINVAL;
		}

		if (decoder->input != *iarg) {
			dprintk(1, KERN_DEBUG "%s: now setting %s input\n",
				I2C_NAME(client),
				*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;

		dprintk(1, KERN_DEBUG "%s: decoder set output\n",
			I2C_NAME(client));

		/* not much choice of outputs */
		if (*iarg != 0) {
			return -EINVAL;
		}
	}
		break;

	case DECODER_ENABLE_OUTPUT:
	{
		int *iarg = arg;
		int enable = (*iarg != 0);

		dprintk(1, KERN_DEBUG "%s: decoder %s output\n",
			I2C_NAME(client), 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;

		dprintk(1,
			KERN_DEBUG
			"%s: decoder set picture bright=%d contrast=%d saturation=%d hue=%d\n",
			I2C_NAME(client), 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);
		}