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

📄 ch7005c.c

📁 CH7005C LINUX 驱动源码 CH7005C LINUX 驱动源码
💻 C
📖 第 1 页 / 共 2 页
字号:
	return 0;
	
err_out_kfree_encoder:
	kfree(encoder);
err_out_kfree_client:
	kfree(client);
err_out:
	return err;
}

/* Called when a new I2C bus found */
static int ch7005c_attach(struct i2c_adapter *adap)
{
	return i2c_probe(adap, &addr_data, ch7005c_detect);
}

/* Called on exit */
static int ch7005c_detach(struct i2c_client *client)
{
	int err;

	if ((err = i2c_detach_client(client)))
		return err;
	kfree(client->data);
	kfree(client);
	return 0;
}

/* Interface to the world */
static int ch7005c_command(struct i2c_client *client,
			     unsigned int cmd, void *arg)
{
	struct ch7005c *dev = (struct ch7005c *)(client->data);

	switch (cmd) {
#ifdef READ_REGISTERS
		case READ_REGISTERS: /* for debugging */
		{
			return ch7005c_read_block(client, arg); /* bytes read */
		}
		case WRITE_REGISTERS: /* for debugging */
		{
			ch7005c_write_block(client, arg, NR_REGISTER);
			return NR_REGISTER;
		}
		case GET_NR_OF_REGISTERS: /* for debugging */
		{
			return NR_REGISTER;
		}
#endif /* READ_REGISTERS */
		case ENCODER_GET_CAPABILITIES:
		{
			struct video_encoder_capability *cap = arg;
			cap->flags = VIDEO_ENCODER_PAL | VIDEO_ENCODER_NTSC 
				| VIDEO_ENCODER_PAL_M | VIDEO_ENCODER_NTSC_J;
			cap->inputs = 1;
			cap->outputs = 2;
			DPRINTK("ENCODER_GET_CAPABILITIES\n");
			break;
		}
		case ENCODER_SET_NORM:	/* SET_DISP_MODE may override this! */
		{
			int norm = *(int*)arg;
			unsigned char blr, idf;
			idf = dev->reg[IDF];
			switch (norm) {
				case VIDEO_ENCODER_PAL:
					blr = 105;
					idf |= 0x40;
					break;
				case VIDEO_ENCODER_NTSC:
				case VIDEO_ENCODER_PAL_M:
					blr = 127;
					idf &= ~0x40;
					break;
				case VIDEO_ENCODER_NTSC_J:
					blr = 100;
					idf |= 0x40;
					break;
				default:
					DPRINTK("invalid norm: %d\n", norm);
					return -EINVAL;
			}
			dev->norm = norm;
			ch7005c_write(client, BLR, blr);
			ch7005c_write(client, IDF, idf);
			DPRINTK("setting BLR: %#x, IDF: %#x\n", blr. idf);
			break;
		}
		case ENCODER_SET_INPUT:
		{
			int input = *(int*)arg;
			if (input != 0) {
				return -EINVAL;
			}
			break;
		}	
		case ENCODER_SET_OUTPUT:
		{
			int output = *(int*)arg;
			unsigned char pmr;
			switch (output) {
				case 0:
					dev->scart_enable = 0;
					break;
				case 1:
					dev->scart_enable = 0x10;
					break;
				default:
					return -EINVAL;
			}
			pmr = (dev->reg[PMR] & 0xef) | dev->scart_enable;
			ch7005c_write(client, PMR, pmr);
			DPRINTK("output set: %d (scart enable: %d)\n", output, dev->scart_enable);
			break;
		}	
		case ENCODER_ENABLE_OUTPUT:
		{
			int enable = *(int*)arg;
			unsigned char pmr;
			if (enable)
				pmr = 0x0b;	/* Normal (on) */
			else
				pmr = 0x0c;	/* Full power down */
			pmr |= dev->scart_enable;
			ch7005c_write(client, PMR, pmr);
			dev->enable = enable;
			DPRINTK("output enable: %d (pmr: %#x)\n", enable, pmr);
			break;
		}
		case ENCODER_SET_CONFIG:	/* TODO: PLLC settings */
		{
			struct ch7005c_config *cfg = (struct ch7005c_config*)arg;
			unsigned char cm, idf, spr, civc;
			if (((cfg->xcm == 0) &&
				(cfg->input_fmt == CH7005C_8_RGB_MPX_24)) ||
			    ((cfg->xcm == 1) && 
				(cfg->input_fmt == CH7005C_16_RGB_16 ||
				 cfg->input_fmt == CH7005C_16_YCRCB_24 ||
				 cfg->input_fmt == CH7005C_15_RGB_15 || 
				 cfg->input_fmt == CH7005C_8_RGB_MPX_24)) ||
			    ((cfg->xcm == 2) && 
				(cfg->input_fmt != CH7005C_8_RGB_MPX_24))) {
				DPRINTK("input data format is not valid!\n");
				return -EINVAL;
			}
			if ((cfg->des == CH7005C_DES_ENABLE) &&
			    (cfg->input_fmt != CH7005C_16_YCRCB_24) &&
			    (cfg->input_fmt != CH7005C_8_YCRCB_MPX_24)) {
				DPRINTK("des value is not valid!\n");
				return -EINVAL;
			}
			cm = 	(cfg->clock_mode << 7) |
				(cfg->clock_mode << 6) | 
				(cfg->mcp << 4) | 
				(cfg->xcm << 2) | 
				(cfg->pcm);
			idf =	(dev->reg[IDF] & 0xd0) |
				(cfg->rgb_bypass << 5) |
				(cfg->input_fmt);
			spr =	(cfg->des << 3) |
				(cfg->sync_direction << 2) |
				(cfg->vert_sync_pol << 1) |
				(cfg->horiz_sync_pol);
			civc =	(dev->reg[CIVC] & 0xfe) | 
				((~cfg->clock_mode) & 0x01);
			ch7005c_write(client, CM, cm);
			ch7005c_write(client, IDF, idf);
			ch7005c_write(client, SPR, spr);
			ch7005c_write(client, CIVC, civc);
			break;
		}
		case ENCODER_SET_DISP_MODE:
		{
			int mode = *(int*)arg;
			unsigned char dmr, mne, m, n, pllc;
			__u32 f = 0;
			if (mode < 0 || mode > 28) {
				DPRINTK("invalid mode: %d\n", mode);
				return -EINVAL;
			}
			dmr = display_modes[mode];
			switch (dev->norm) {
				case VIDEO_ENCODER_PAL:
				case VIDEO_ENCODER_NTSC:
					f = fsci[mode];
					break;
				case VIDEO_ENCODER_PAL_M:
				case VIDEO_ENCODER_NTSC_J:
					dmr |= 0x10;
					f = fsci_mj[mode];
					break;
				default:
					DPRINTK("internal error, norm: %d\n", dev->norm);
					return -EINVAL;
			}
			m = pll_m[mode];
			n = pll_n[mode];
			mne = ((n & 0x300) >> 7) | ((m & 0x100) >> 8);
			pllc = (dev->reg[PLLC] & 0xef) | (pllcap[mode] << 4);
			ch7005c_write(client, DMR, dmr);
			ch7005c_write(client, MNE, mne);
			ch7005c_write(client, PLLM, m & 0xff);
			ch7005c_write(client, PLLN, n & 0xff);
			ch7005c_write(client, PLLC, pllc);
			ch7005c_write(client, FSCI0, f & 0x0f);
			f >>= 4;
			ch7005c_write(client, FSCI1, f & 0x0f);
			f >>= 4;
			ch7005c_write(client, FSCI2, f & 0x0f);
			f >>= 4;
			ch7005c_write(client, FSCI3, f & 0x0f);
			f >>= 4;
			ch7005c_write(client, FSCI4, f & 0x0f);
			f >>= 4;
			ch7005c_write(client, FSCI5, f & 0x0f);
			f >>= 4;
			ch7005c_write(client, FSCI6, f & 0x0f);
			f >>= 4;
			ch7005c_write(client, FSCI7, f & 0x0f);
			DPRINTK("new mode: %d (dmr: %#x, mne: %#x, m: %#x, n: %#x, pllc: %#x)\n", mode, dmr, mne, m, n, pllc);
			break;
		}
		case ENCODER_SET_FLICKER_FILTER:
		{
			struct ch7005c_filter *filter = (struct ch7005c_filter*)arg;
			int ft, fy, fc;
			unsigned char ffr;
			ft = filter->text_enhancement;
			fy = filter->luma;
			fc = filter->chroma;
			if (ft < CH7005C_FILTER_MIN || 
			    ft > CH7005C_FILTER_MAX ||
			    fy < CH7005C_FILTER_MIN ||
			    fy > CH7005C_FILTER_MAX ||
			    fc < CH7005C_FILTER_MIN ||
			    fc > CH7005C_DOTCRAWL_RED) {
				DPRINTK("invalid filter mode\n");
				return -EINVAL;
			}
			ffr =	(fc << 4) |
				(fy << 2) |
				(2 - ft);
			ch7005c_write(client, FFR, ffr);
			DPRINTK("flicker filter: %#x\n", ffr);
			break;
		}
		case ENCODER_SET_POS: /* TODO: verify values better, DS/BCO handling */
		{
			struct ch7005c_pos *pos = (struct ch7005c_pos*)arg;
			unsigned char po;
			if (pos->start_active_video > 511 ||
			    pos->horiz_pos > 511 ||
			    pos->vert_pos > 511) {
				DPRINTK("invalid position! \n");
				return -EINVAL;
			}
			po = 	((pos->start_active_video & 0x100) >> 6) |
				((pos->horiz_pos & 0x100) >> 7) |
				((pos->vert_pos & 0x100) >> 8);
			ch7005c_write(client, SAV, pos->start_active_video & 0xff);
			ch7005c_write(client, HPR, pos->horiz_pos & 0xff);
			ch7005c_write(client, VPR, pos->vert_pos & 0xff);
			ch7005c_write(client, PO, po);
			DPRINTK("position set\n");
			break;
		}
		case ENCODER_SET_CONTRAST:
		{
			int cont = *(int*)arg;
			if (cont < 0 || cont > 7) {
				DPRINTK("invalid contrast: %d\n", cont);
				return -EINVAL;
			}
			ch7005c_write(client, CE, cont);
			DPRINTK("contrast adjusted to: %d\n", cont);
			break;
		}
		case ENCODER_DETECT_CONNECTIONS:
		{
			int *conn = arg;
			if (!dev->enable) {
				DPRINTK("ENCODER_DETECT_CONNECTIONS is not possible with disabled device!\n");
				return -EINVAL;
			}
			ch7005c_write(client, CDR, 0x01);
			/* udelay(1); */
			ch7005c_write(client, CDR, 0x00);
			*conn = (~ch7005c_read(client, CDR)) & 0x0e;
			DPRINTK("detected connections: %#x\n", *conn);
			break;
		}
		default:
		{
			DPRINTK("unknown command!\n");
			return -EINVAL;
		}
	}
	return 0;
}

static void ch7005c_inc_use(struct i2c_client *client)
{
	MOD_INC_USE_COUNT;
}

static void ch7005c_dec_use(struct i2c_client *client)
{
	MOD_DEC_USE_COUNT;
}



/*---------------------------------------------------------------------- 
 *	Modularization
 *----------------------------------------------------------------------*/

MODULE_AUTHOR("Ferenc Bakonyi <fero@drama.obuda.kando.hu>");
MODULE_DESCRIPTION("CH7005C driver");
MODULE_LICENSE("GPL");

int __init init_ch7005c(void) 
{
	return i2c_add_driver(&i2c_driver_ch7005c);
}

void __exit cleanup_ch7005c(void) 
{
	i2c_del_driver(&i2c_driver_ch7005c);
}

module_init(init_ch7005c);
module_exit(cleanup_ch7005c);

⌨️ 快捷键说明

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