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

📄 ch7013.c

📁 本驱动为7013 tvout驱动
💻 C
字号:
/** * @file ch7013.c * @brief Source file for CH7013B tvout driver. * * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA * * Copyright (C) 2006 Sitek Hengke Electronics Wuxi. *                              http://www.ihanker.com * Modification history: *  * Nov.  29, 2006.  Gary * 	Initial version of this file. *  */#include <linux/kernel.h>#include <linux/module.h>#include <linux/mm.h>#include <linux/slab.h>#include <linux/init.h>#include <linux/i2c.h>#include <linux/i2c-algo-bit.h>#include <linux/i2c-id.h>#include <linux/poll.h>#include <linux/miscdevice.h>#include <linux/proc_fs.h>#include <linux/delay.h>#include <asm/types.h>#include <asm/hardware.h>#include <asm/arch/clock.h>#include "mx2fb.h"#include "ch7013.h"#define MODULE_NAME	"tvout"static int g_tvout_major = 0;static lcdc_regs_t g_lcdc_regs;/*************************************************************************************************	i2c related*************************************************************************************************///CH7013 i2c addr//ADDR   Serial Address Selected//  1        111 0101 = 75h          //high: 0xEA(write), 0xEB(read)//  0        111 0110 = 76h	     // low:  0xEC(write), 0xED(read)#define CH7013_MXC_I2C_FLAG_POLLING	0x02	/* if set, is polling mode; else is interrupt mode */#define CH7013_I2C_ADDR  0x76	//0xECstatic int ch7013_i2c_attach (struct i2c_adapter * adap);static struct i2c_driver ch7013_i2c_driver = {	.driver = {		   .owner = THIS_MODULE,		   .name = "ch7013 driver",		   },	.attach_adapter = &ch7013_i2c_attach,	.detach_client = NULL,};static struct i2c_client ch7013_i2c_client = {	.name = "ch7013 I2C dev",	.addr = CH7013_I2C_ADDR,	.driver = &ch7013_i2c_driver,	.flags = 0,};static int ch7013_i2c_attach(struct i2c_adapter *adap){       printk("ch7013_i2c_attach begin!\n");	if (memcmp(adap->name, "MXC I2C Adapter", 15) != 0 ) {		printk("memcmp adapter name failed\n");		return -ENODEV;	}	ch7013_i2c_client.adapter = adap;	if (i2c_attach_client(&ch7013_i2c_client)) {		printk("ch7013: i2c_attach_client() failed.\n");		//i2c_del_driver(&ch7013_i2c_driver);		return -1;	} 	return 0;}/*! * @brief Function to read one byte from TV encoder registers on the i2c bus * @param     client	I2C client structure * @param     reg	The register number/CH7013 register address * @param     value	Pointer to buffer to receive the read data/register value */static int ch7013_i2c_read(unsigned char reg, unsigned char *buf){	struct i2c_msg msg[2];	int ret;	msg[0].addr = ch7013_i2c_client.addr;	msg[0].len = 1;	msg[0].buf = &reg;	msg[0].flags = CH7013_MXC_I2C_FLAG_POLLING;	msg[1].addr = ch7013_i2c_client.addr;	msg[1].len = 2;	msg[1].buf = buf;	msg[1].flags = I2C_M_RD | CH7013_MXC_I2C_FLAG_POLLING;		ret = i2c_transfer(ch7013_i2c_client.adapter, msg, 2);	if (ret >= 0)		return 0;	return ret;}/*! * @brief Function to write one byte to a TV encoder register on the i2c bus * @param     client	I2C client structure * @param     reg	The register number/CH7013 register address * @param     value	The value to write */ static int ch7013_i2c_write(unsigned char reg, unsigned char data){	struct i2c_msg msg[2];	int ret;	msg[0].addr = ch7013_i2c_client.addr;	msg[0].len = 1;	//msg[0].buf[0] = reg;	msg[0].buf = &reg;	msg[0].flags = 0;	msg[1].addr = ch7013_i2c_client.addr;	msg[1].len = 2;	//msg[1].buf[0] = data;	msg[1].buf = &data;	msg[1].flags = 0;	ret = i2c_transfer(ch7013_i2c_client.adapter, msg, 2);	if (ret >= 0)		return 0;	return ret;}void	ch7013_i2c_init(void){	/* check for deferred I2C registration */	int err;	if (err = i2c_add_driver(&ch7013_i2c_driver)) 		printk("ch7013: driver registration failed\n");	return ;}void ch7013_i2c_cleanup(void){	i2c_detach_client(&ch7013_i2c_client );	i2c_del_driver(&ch7013_i2c_driver);}/*************************************************************************************************	End of i2c related*************************************************************************************************////////////////////////////////////////////////////////////////////////TVOUT CH7013 Part////////////////////////////////////////////////////////////////////static int ch7013_i2c_program(struct i2c_client *client);static void ch7013_hw_init(void);static void ch7013_hw_exit(void);static void ch7013_save_lcdc(void);static ch7013_fixed_table_t ctable[] ={	{0x60, 0x2A, 0x50, 0x74, 0x31, 0x81, 0x18, 0x2D, 0x40,  0x0D, 0x14, 0x300AE7C4, 0x10, 0x00},	//display mode 13	{0x61, 0x2A, 0x50, 0x44, 0x31, 0x81, 0x36, 0x2C, 0x40,  0x04, 0x09, 0x266F1FD0, 0x10, 0x00},	//display mode 14	{0x69, 0x2A, 0x50, 0x6A, 0x30, 0x81, 0x1F, 0xF9, 0x40,  0x3F, 0x6E, 0x25249249, 0x00, 0x00},	//display mode 16	{0x6A, 0x2A, 0x50, 0x64, 0x30, 0x81, 0x2D, 0xFD, 0x40,  0x3F, 0x7E, 0x20800000, 0x00, 0x00},	//display mode 17};static int ch7013_i2c_program(struct i2c_client *client){	int idx;	unsigned char chip_ver;	u8 reg;		idx = 3;	ch7013_i2c_write(0x0E, 0x00);		//soft reset	//mdelay(1);	ch7013_i2c_write(0x0E, 0x0B);		//all are active	//mdelay(1);	reg = 0x25;	ch7013_i2c_read(reg, &chip_ver);	printk("Chip version ID(0x22)= 0x%X\n", chip_ver);	ch7013_i2c_write(0x00, ctable[idx].DMR);	//display mode	ch7013_i2c_write(0x01, ctable[idx].FFR);	//flicker filter settings	ch7013_i2c_write(0x04, 0x00);	                     //Input data format		 16bit 565	ch7013_i2c_write(0x06, ctable[idx].CM);	//clock mode	ch7013_i2c_write(0x07, ctable[idx].SAV);	//start of active video register	ch7013_i2c_write( 0x08, ctable[idx].PO);	//position overflow	ch7013_i2c_write( 0x09, ctable[idx].BLR);	//black level	ch7013_i2c_write( 0x0A, ctable[idx].HPR);	//horizontal position	ch7013_i2c_write( 0x0B, ctable[idx].VPR);	//vertical position	ch7013_i2c_write( 0x13, ctable[idx].MNE);	//PLLM and PLLN	ch7013_i2c_write( 0x14, ctable[idx].PLLM);	ch7013_i2c_write( 0x15, ctable[idx].PLLN);	ch7013_i2c_write( 0x20, ctable[idx].PLLC);	//PLL control	ch7013_i2c_write( 0x21, ctable[idx].CIVC);	//turn off CIV	ch7013_i2c_write( 0x18, (ctable[idx].FSCI & 0xF0000000) >> 28);	ch7013_i2c_write( 0x19, (ctable[idx].FSCI & 0x0F000000) >> 24);	ch7013_i2c_write( 0x1A, (ctable[idx].FSCI & 0x00F00000) >> 20);	ch7013_i2c_write( 0x1B, (ctable[idx].FSCI & 0x000F0000) >> 16);	ch7013_i2c_write( 0x1C, (ctable[idx].FSCI & 0x0000F000) >> 12);	ch7013_i2c_write( 0x1D, (ctable[idx].FSCI & 0x00000F00) >> 8);	ch7013_i2c_write( 0x1E, (ctable[idx].FSCI & 0x000000F0) >> 4);	ch7013_i2c_write( 0x1F, ctable[idx].FSCI & 0x0000000F);		return 0;}//This function config LCDC registers to fit TVOUT output.static void ch7013_set_lcdc(void){	unsigned int val;	unsigned int reg;	/* Size register */	__raw_writel(0x128001E0, LCDC_REG(LCDC_LSR));	// refer to CONFIG_FB_64_TFTLCD	/* Virtual page width register */	__raw_writel(0x140, LCDC_REG(LCDC_LVPWR));		// refer to CONFIG_FB_64_TFTLCD	//mxc_set_clocks_div(LCDC_CLK, 1);	reg = __raw_readl(IO_ADDRESS(0x10027000) + 0x1c);	reg = (reg & (~(0x3f << 16)));	__raw_writel(reg, IO_ADDRESS(0x10027000) + 0x1c);		/* Panel configuration register */	__raw_writel(0xFA380089, LCDC_REG(LCDC_LPCR));	//__raw_writel(0xFAE000C1, LCDC_REG(LCDC_LPCR));	// refer to CONFIG_FB_64_TFTLCD	/* Horizontal and vertical configuration register */	val = (13<<26) | (25<<8) | (98);	printk("LHCR: 0x%x\n", val);	__raw_writel(val, LCDC_REG(LCDC_LHCR));        printk("LHCR = 0x%x\n",(*(unsigned long *)(LCDC_REG(LCDC_LHCR))));	//__raw_writel(0xB0002008, LCDC_REG(LCDC_LHCR));	//val = (2<<26) | (46<<8) | (54);	val = (2<<26) | (43<<8) | (43);	printk("LVCR: 0x%x\n", val);	__raw_writel(val, LCDC_REG(LCDC_LVCR));	//__raw_writel(0x0200110A, LCDC_REG(LCDC_LVCR));	/* Sharp configuration register */	//__raw_writel(0x04120300, LCDC_REG(LCDC_LSCR));	/* Refresh mode control reigster */	__raw_writel(0x00000000, LCDC_REG(LCDC_LRMCR));	/* PWM contrast control register */	__raw_writel(0x00A903FF, LCDC_REG(LCDC_LPCCR));	/* DMA control register */	__raw_writel(0x00030008, LCDC_REG(LCDC_LDCR));}/** * @brief Save the register values/status that might be changed by tvout */static void ch7013_save_lcdc(void){	//Save lcdc registers	g_lcdc_regs.LSSAR = __raw_readl(LCDC_REG(LCDC_LSSAR));	g_lcdc_regs.LSR = __raw_readl(LCDC_REG(LCDC_LSR));	g_lcdc_regs.LVPWR = __raw_readl(LCDC_REG(LCDC_LVPWR));	g_lcdc_regs.LPCR = __raw_readl(LCDC_REG(LCDC_LPCR));	g_lcdc_regs.LHCR = __raw_readl(LCDC_REG(LCDC_LHCR));	g_lcdc_regs.LVCR = __raw_readl(LCDC_REG(LCDC_LVCR));	g_lcdc_regs.LSCR = __raw_readl(LCDC_REG(LCDC_LSSAR));	g_lcdc_regs.LPCCR = __raw_readl(LCDC_REG(LCDC_LPCCR));	g_lcdc_regs.LRMCR = __raw_readl(LCDC_REG(LCDC_LRMCR));	g_lcdc_regs.LDCR = __raw_readl(LCDC_REG(LCDC_LDCR));	g_lcdc_regs.LGWDCR = __raw_readl(LCDC_REG(LCDC_LGWDCR));	}static void ch7013_hw_init(void){	ch7013_i2c_init();	printk("ch7013_i2c_init over!\n");		ch7013_save_lcdc();;	printk("ch7013_save_lcdc over!\n");	ch7013_set_lcdc();	printk("ch7013_set_lcdc over!\n");	mdelay(10);	ch7013_i2c_program(&ch7013_i2c_client);	printk("ch7013_i2c_program over!\n");}static void ch7013_hw_exit(void){	ch7013_i2c_cleanup();}static int ch7013_open(struct inode * inode, struct file * filp){	return 0;}static int ch7013_release(struct inode * inode, struct file * filp){	return 0;}static int ch7013_ioctl(struct inode * inode, struct file *filp, u_int cmd, u_long arg){	int ret = 0;		return ret;}struct file_operations g_tvout_fops = {	owner:		THIS_MODULE,	ioctl:		ch7013_ioctl,	open:		ch7013_open,	release:		ch7013_release,};static int __init ch7013_init(void){	printk("MX27 CH7013 tvout driver.\n"); 	g_tvout_major = register_chrdev(0, MODULE_NAME, &g_tvout_fops); 	if (g_tvout_major < 0) { 		printk("Unable to register %s driver.\n",MODULE_NAME);		remove_proc_entry(MODULE_NAME, NULL); 		return -ENODEV; 	} else {		printk("/dev/tvout major device number is: %d\n", g_tvout_major); 	}	ch7013_hw_init();		return 0;}static void __exit ch7013_exit(void){	ch7013_hw_exit();	if (g_tvout_major > 0) {		unregister_chrdev(g_tvout_major, MODULE_NAME);	}}module_init(ch7013_init);module_exit(ch7013_exit);MODULE_DESCRIPTION("MX27 TVOUT CH7013 Driver ");MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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