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

📄 ch7005c.c

📁 CH7005C LINUX 驱动源码 CH7005C LINUX 驱动源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* ------------------------------------------------------------------------- */
/* ch7005c.c I2C driver for Chrontel CH7005C video encoder chips	     */
/* ------------------------------------------------------------------------- */
/*   Copyright (C) 2000 Ferenc Bakonyi <fero@drama.obuda.kando.hu>
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation; either version 2 of the License, or
 *   (at your option) any later version.
 *   
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *   
 *   You should have received a copy of the GNU General Public License
 *   along with this program; if not, write to the Free Software
 *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.		     */
/* ------------------------------------------------------------------------- */

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/videodev.h>

#include "rivatv.h"	/* HACK for register dump! */
#include "ch7005c.h"

#undef DPRINTK
#define DPRINTK(x...)


/*----------------------------------------------------------------------
 *	CH7005C I2C 'driver' driver
 *----------------------------------------------------------------------*/

static int ch7005c_attach(struct i2c_adapter *adap);
static int ch7005c_detach(struct i2c_client *client);
static int ch7005c_command(struct i2c_client *client, 
		unsigned int cmd, void *arg);
static void ch7005c_inc_use(struct i2c_client *client);
static void ch7005c_dec_use(struct i2c_client *client);

/* CH7005C address: 0x75 */
static unsigned short normal_i2c[] = {0x75, I2C_CLIENT_END};
static unsigned short normal_i2c_range[] = {I2C_CLIENT_END};

/* Magic definition of all other I2C variables and things */
I2C_CLIENT_INSMOD;

/* Number of CH7005C registers */
#define NR_REGISTER	64

/* CH7005C register map */
#define	DMR	0x00
#define	FFR	0x01
#define	VBW	0x03
#define	IDF	0x04
#define	CM	0x06
#define	SAV	0x07
#define	PO	0x08
#define	BLR	0x09
#define	HPR	0x0a
#define	VPR	0x0b
#define	SPR	0x0d
#define	PMR	0x0e
#define	CDR	0x10
#define	CE	0x11
#define	MNE	0x13
#define	PLLM	0x14
#define	PLLN	0x15
#define	BCO	0x16
#define	FSCI7	0x18
#define	FSCI6	0x19
#define	FSCI5	0x1a
#define	FSCI4	0x1b	/* TODO: P-OUTP */
#define	FSCI3	0x1c	/* TODO: DSEN */
#define	FSCI2	0x1d
#define	FSCI1	0x1e
#define	FSCI0	0x1f
#define	PLLC	0x20
#define	CIVC	0x21
#define	CIV	0x22
#define	VID	0x25
#define	TR	0x26
#define	AR	0x3f

/* Initial register values */
unsigned char init_regs[] = {
	0x6a,	/* DMR		Mode 17 (640x480, NTSC, 7/8) */
	0x32,	/* FFR */
	0x00,	/* unused */
	0x00,	/* VBW		TODO */
	0x00,	/* IDF		16-bit non-multiplexed RGB (16-bit color, 565) */
	0x00,	/* unused */
	0x10,	/* CM		slave */
	0x00,	/* SAV */
	0x00,	/* PO */
	0x7f,	/* BLR		127 for NTSC */
	0x00,	/* HPR */
	0x00,	/* VPR */
	0x00,	/* unused */
	0x00,	/* SPR		syncs are inputs and active low */
	0x0b,	/* PMR		output enabled, scart disabled */
	0x00,	/* unused */
	0x00,	/* CDR */
	0x03,	/* CE */
	0x00,	/* unused */
	0x00,	/* MNE */
	0x41,	/* PLLM		BUG? or 0x3f ??? */
	0x80,	/* PLLN		BUG? or 0x7e ??? */
	0x00,	/* BCO		TODO: implement */
	0x00,	/* unused */
	0x00,	/* FSCI7 */
	0x00,	/* FSCI6 */
	0x00,	/* FSCI5 */
	0x00,	/* FSCI4 */
	0x00,	/* FSCI3 */
	0x00,	/* FSCI2 */
	0x00,	/* FSCI1 */
	0x00,	/* FSCI0 */
	0x0a,	/* PLLC	*/
	0x01	/* CIVC */
};

/* CH7005C instance */
struct ch7005c {
	int enable;			/* output enabled */
	int scart_enable;		/* output is scart */
	__u32 norm;			/* video norm */
	unsigned char reg[NR_REGISTER];	/* local copy of ch7005c's registers*/
};

/* Standard display modes */
static unsigned char display_modes[] = {
		/* IR VOS SR  */
	0x00,	/* 000 00 000 */
	0x01,	/* 000 00 001 */
	0x08,	/* 000 01 000 */
	0x09,	/* 000 01 001 */
	0x20,	/* 001 00 000 */
	0x21,	/* 001 00 001 */
	0x28,	/* 001 01 000 */
	0x29,	/* 001 01 001 */
	0x42,	/* 010 00 010 */
	0x41,	/* 010 00 001 */
	0x48,	/* 010 01 000 */
	0x49,	/* 010 01 001 */
	0x4a,	/* 010 01 010 */
	0x60,	/* 011 00 000 */
	0x61,	/* 011 00 001 */
	0x63,	/* 011 00 011 */
	0x69,	/* 011 01 001 */
	0x6a,	/* 011 01 010 */
	0x6b,	/* 011 01 011 */
	0x81,	/* 100 00 001 */
	0x83,	/* 100 00 011 */
	0x84,	/* 100 00 100 */
	0x8b,	/* 100 01 011 */
	0x8c,	/* 100 01 100 */
	0x8d,	/* 100 01 101 */
	0xa1,	/* 101 00 001 TODO: extra checks for IDF */
	0xa9,	/* 101 01 001 TODO: extra checks for IDF */
	0xc1,	/* 110 00 001 TODO: extra checks for IDF */
	0xc9	/* 110 01 001 TODO: extra checks for IDF */
};

/* PLL M values for each display mode */
static unsigned int pll_m[] = {
	13, 4, 89, 63, 26, 138, 63, 33, 61, 3, 63, 11, 89, 13, 4,
	3, 63, 63, 89, 313, 33, 103, 33, 19, 89, 33, 33, 197, 2
};

/* PLL N values for each display mode */
static unsigned int pll_n[] = {
	20, 9, 126, 110, 53, 339, 106, 70, 108, 9, 94, 22, 190, 20, 9,
	9, 110, 126, 190, 647, 86, 284, 94, 62, 302, 31, 31, 242, 2
};

/* PLLCAP values for each display mode */
static unsigned char pllcap[] = {
	1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1,
	1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1
};

/* FSCI values for each display mode */
static __u32 fsci[] = {
	806021060, 644816848, 763363328, 623153737, 601829058,
	485346014, 574429782, 463962517, 677057690, 537347373,
	646233505, 516986804, 452363454, 806021060, 644816848,
	537347373, 623153737, 545259520, 508908885, 645499916,
	528951320, 488262757, 521957831, 469762048, 428554851,
	705268427, 569408543, 1073747879, 1073741824
};

/* FSCI values for PAL-M and NTSC-J display modes */
static __u32 fsci_mj[] = {
	651209077, 520967262, 762524467, 622468953, 486236111,
	392125896, 573798541, 463452668, 547015625, 434139385,
	645523358, 516418687, 451866351, 651209077, 520967262,
	434139385, 622468953, 544660334, 508349645, 521519134,
	427355957, 394482422, 521384251, 469245826, 428083911,
	569807942, 568782819, 867513766, 1072561888
};

/*  For registering the I2C 'driver' driver */
static struct i2c_driver i2c_driver_ch7005c = {
	name:		"CH7005C",
	id:		I2C_DRIVERID_CH7005,
	flags:		I2C_DF_NOTIFY,
	attach_adapter:	ch7005c_attach,
	detach_client:	ch7005c_detach,
	command:	ch7005c_command,
	inc_use:	ch7005c_inc_use,
	dec_use:	ch7005c_dec_use
};

/* Template for new clients */
static struct i2c_client ch7005c_client_template = {
	name:		"CH7005C",
	id:		-1,
	flags:		0,
	addr:		0,
	adapter:	NULL,
	driver:		&i2c_driver_ch7005c,
	data:		NULL /* struct ch7005c *data */
};

/* Unique ID allocation */
static int ch7005c_id = 0;



/* Helper functions */

/* Read from a register */
static int ch7005c_read(struct i2c_client *client, unsigned char subaddr)
{
	return i2c_smbus_read_byte_data(client, subaddr);
}

/* Write to a register */
static int ch7005c_write(struct i2c_client *client, unsigned char subaddr, unsigned char data)
{
	struct ch7005c *dev = (struct ch7005c *)(client->data);

	dev->reg[subaddr] = data;
	return i2c_smbus_write_byte_data(client, subaddr, data);
}

/* Read all registers */
#ifdef READ_REGISTERS
static int ch7005c_read_block(struct i2c_client *client, unsigned char *data)
{
	int i;

	for (i = 0 ; i < NR_REGISTER ; i++)
    		data[i] = i2c_smbus_read_byte_data(client, i);
	return NR_REGISTER;
}
#endif

/* Write to a register block */
static int ch7005c_write_block(struct i2c_client *client, unsigned char *data, unsigned int len)
{
	struct ch7005c *dev = (struct ch7005c *)(client->data);
	int i, err;

	if (len > NR_REGISTER) len = NR_REGISTER;
	for (i = 0 ; i < len ; i++) {
		if ((err = i2c_smbus_write_byte_data(client, i, data[i])))
			return err;
    		dev->reg[i] = data[i];
	}
	return 0;
}

/* I2C driver functions */

/* Called when a 'CH7005C like' device found */
static int ch7005c_detect(struct i2c_adapter *adap, int addr, unsigned short flags, int kind)
{
	int err = 0;
	struct i2c_client *client;
	struct ch7005c *encoder;
	int version;

	if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_READ_BYTE_DATA | 
	        		          I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
		goto err_out;

	client = kmalloc(sizeof(*client), GFP_KERNEL);
	if (client == NULL) {
		err = -ENOMEM;
		goto err_out;
	}
	
	memcpy(client, &ch7005c_client_template, sizeof(*client));
	client->adapter = adap;
        client->addr = addr;
        client->id = ch7005c_id++;

	if (kind < 0) {
		version = i2c_smbus_read_byte_data(client, VID);
		if (version == -1)
			goto err_out_kfree_client;
		if (version == 0x3a) {
			printk("ch7005c: video encoder chip found. Chip version: %#x\n", version);
		} else {
			printk("ch7005c: unknown CH700x chip found. (Maybe 7003?) Chip version: %#x\n", version);
			goto err_out_kfree_client;
		}
	} else {
		printk("ch7005c: detection skipped\n");
	}
	
	encoder = kmalloc(sizeof(struct ch7005c), GFP_KERNEL);
	if (encoder == NULL) {
		err = -ENOMEM;
		goto err_out_kfree_client;
	}

	memset(encoder, 0, sizeof(struct ch7005c));
	encoder->enable = 1;
	encoder->scart_enable = 0;
	encoder->norm = VIDEO_ENCODER_NTSC;
	client->data = encoder;

	if (ch7005c_write_block(client, init_regs, sizeof(init_regs)))
		goto err_out_kfree_encoder;

	if ((err = i2c_attach_client(client)))
		goto err_out_kfree_encoder;

⌨️ 快捷键说明

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