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

📄 mx21_ch7013.c

📁 ch7013数据手册和21下的驱动
💻 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.sitek.cn * 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/pxa-regs.h>#include "tvout.h"#include "ch7013.h"extern int pxa27x_set_cpufreq(unsigned int, unsigned int, unsigned int, unsigned int, unsigned int);	extern unsigned int get_clk_frequency_khz(int info);#define MODULE_NAME	"tvout"static int g_tvout_major = 0;static lcdc_regs_t g_lcdc_regs;/*************************************************************************************************	i2c related*************************************************************************************************/#define I2C_DRIVERID_I2CCH7013 0xF000#define I2C_M_READ 0x01#define I2C_M_WT 0x02//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_I2C_ADDR  0x76	//0xECstatic int i2c_ch7013_attach_adapter (struct i2c_adapter * adap);static struct i2c_driver i2c_ch7013_driver ={	name:		"i2c-ch7013 client driver",	id:		I2C_DRIVERID_I2CCH7013,	flags:		I2C_DF_NOTIFY,	attach_adapter:	i2c_ch7013_attach_adapter,	detach_client:	NULL,	command:	NULL};static struct i2c_client i2c_ch7013_client ={	name:		"i2c-ch7013 client",	id:		2,	flags:		0,	addr:		-1,	adapter:	NULL,	driver:		&i2c_ch7013_driver};static int i2c_ch7013_attach_adapter (struct i2c_adapter * adap){	if (memcmp(adap->name, "PXA i2c adapter", 15) != 0 ) {		return -ENODEV;	}	i2c_ch7013_client.adapter = adap;	return 0;}void i2c_ch7013_init(void){	/* 	 * set the address of the CH7013 to the client	 */	i2c_ch7013_client.addr = CH7013_I2C_ADDR;	/* 	 * call the i2c_add_driver() to register the driver 	 * to the Linux I2C system	 */	if (i2c_add_driver( &i2c_ch7013_driver ) != 0) {		printk("I2C add driver failed\n");		return;	}	/* 	 * attach the client to the adapter by calling the i2c_attach_client() 	 * function of the Linux I2C system	 */	if (i2c_attach_client(&i2c_ch7013_client ) != 0) {			printk("I2C attach client failed\n");		i2c_del_driver(&i2c_ch7013_driver);		return;	}}void i2c_ch7013_cleanup(void){	i2c_detach_client(&i2c_ch7013_client );	i2c_del_driver(&i2c_ch7013_driver);}/** * @brief Write one byte to CH7013 register * * @param reg	CH7013 register address * @param data  Data to be written to the register */static int i2c_ch7013_write(unsigned int reg, unsigned char data){	struct i2c_msg msg;	char buf[2];	int ret;	/* 	 * store the register value to the first address of the buffer 	 * the adapter/algorithm driver will regard the first byte 	 * as the register value 	 */	buf[0] = (char)reg;	buf[1] = data;			/* 	 * initialize the message structure	 */	msg.addr = i2c_ch7013_client.addr;	msg.flags = I2C_M_WT;	msg.len = 2;	msg.buf = buf;		ret = i2c_transfer( i2c_ch7013_client.adapter, &msg, 1 );	return ret;}static int i2c_ch7013_read(unsigned int reg_offset, unsigned char *buf){	struct i2c_msg msg[2]  = {		{ i2c_ch7013_client.addr, 0,        1, &reg_offset },		{ i2c_ch7013_client.addr, I2C_M_RD, 1, buf }	};	if (i2c_transfer( i2c_ch7013_client.adapter, msg, 2 ) == 2)		return 2;	else		return 0;}/*************************************************************************************************	End of i2c related*************************************************************************************************////////////////////////////////////////////////////////////////////////TVOUT CH7013 Part////////////////////////////////////////////////////////////////////static int ch7013_program(void);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_program(void){	int idx;	unsigned char chip_ver;			idx = 3;	i2c_ch7013_write(0x0E, 0x00);			//soft reset	mdelay(1);	i2c_ch7013_write(0x0E, 0x0B);			//all are active	mdelay(1);		i2c_ch7013_read(0x25, &chip_ver);	printk("Chip version ID(0x22)= 0x%X", chip_ver);	i2c_ch7013_write(0x00, ctable[idx].DMR);	//display mode	i2c_ch7013_write(0x01, ctable[idx].FFR);	//flicker filter settings	i2c_ch7013_write(0x04, 0x00);	                     //Input data format		 16bit 565	i2c_ch7013_write(0x06, ctable[idx].CM);	//clock mode	i2c_ch7013_write(0x07, ctable[idx].SAV);	//start of active video register	i2c_ch7013_write(0x08, ctable[idx].PO);	//position overflow	i2c_ch7013_write(0x09, ctable[idx].BLR);	//black level	i2c_ch7013_write(0x0A, ctable[idx].HPR);	//horizontal position	i2c_ch7013_write(0x0B, ctable[idx].VPR);	//vertical position	i2c_ch7013_write(0x13, ctable[idx].MNE);	//PLLM and PLLN	i2c_ch7013_write(0x14, ctable[idx].PLLM);	i2c_ch7013_write(0x15, ctable[idx].PLLN);	i2c_ch7013_write(0x20, ctable[idx].PLLC);	//PLL control	i2c_ch7013_write(0x21, ctable[idx].CIVC);	//turn off CIV	i2c_ch7013_write(0x18, (ctable[idx].FSCI & 0xF0000000) >> 28);	i2c_ch7013_write(0x19, (ctable[idx].FSCI & 0x0F000000) >> 24);	i2c_ch7013_write(0x1A, (ctable[idx].FSCI & 0x00F00000) >> 20);	i2c_ch7013_write(0x1B, (ctable[idx].FSCI & 0x000F0000) >> 16);	i2c_ch7013_write(0x1C, (ctable[idx].FSCI & 0x0000F000) >> 12);	i2c_ch7013_write(0x1D, (ctable[idx].FSCI & 0x00000F00) >> 8);	i2c_ch7013_write(0x1E, (ctable[idx].FSCI & 0x000000F0) >> 4);	i2c_ch7013_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 reg_lccr0;	unsigned int reg_lccr1;	unsigned int reg_lccr2;	unsigned int reg_lccr3;	unsigned int PCD;		LCCR0 = 0;	LCCR1 = 0;	LCCR2 = 0;	LCCR3 = 0;	LCCR4 = 0;	LCCR5 = 0x3f3f3f3f;	FSADR0 = g_lcdc_regs.fsadr0;	FDADR0 = g_lcdc_regs.fdadr0;	FIDR0 = g_lcdc_regs.fidr0;	LDCMD0 = g_lcdc_regs.ldcmd0;		// Configure the LCD Controller Control Registers	PCD = 2;		reg_lccr0 = (LCCR0_BM | LCCR0_PAS | \                      LCCR0_EFM | LCCR0_IUM | LCCR0_SFM | LCCR0_LDM);	LCCR0 = reg_lccr0;  	 reg_lccr1 = (LCD_PPL(640) | LCD_HSW(0x35) | LCD_ELW(0x10)  | LCD_BLW(0x4B));	 LCCR1 = reg_lccr1; 	reg_lccr2 = (LCD_LPP(480) | LCD_VSW(0x30) | LCD_EFW(0x22)  | LCD_BFW(0x20));   	LCCR2 = reg_lccr2;  	reg_lccr3 = (LCD_PCD(PCD)  | LCD_BPP(4) |LCD_OEP|LCD_PCP | LCD_PDFOR(PDFOR_00)); 	LCCR3 = reg_lccr3; 	 	LCCR4 = 0x80000000;		// enable LCD Controller	LCCR0 |= LCD_ENB;		//printk("lccr0: 0x%08x \n", LCCR0);	//printk("lccr1: 0x%08x \n", LCCR1);	//printk("lccr2: 0x%08x \n", LCCR2);	//printk("lccr3: 0x%08x \n", LCCR3);	//printk("lccr4: 0x%08x \n", LCCR4);}#if 0static void ch7013_regs_dump(void){	unsigned int k;	unsigned char v;		for (k = 0x00; k <= 0x29; k++) {		i2c_ch7013_read(k, &v);		printk("REG:%x = 0x%x \n", k, v);	}}#endif//This function modify PXA27x CPU Clock and LCDC Clockstatic void ch7013_change_cpufreq(void){	//unsigned int CCCR_L;	//int LCLK = 0;	unsigned int l = 26;	unsigned int n2 = 3;	unsigned int t = 2; 	unsigned int b = 0;	unsigned int a = 1;	unsigned int memclk, lcdclk;		//printk("*******************First**************************\n");	//get_clk_frequency_khz(1);	//memclk = get_memclk_frequency_10khz();	//lcdclk = get_lcdclk_frequency_10khz();	//printk("memclk = %d,  lcdclk = %d\n", memclk, lcdclk);	ch7013_save_lcdc();	// 1. turn off LCDC clock before change 	CKEN &= (~0x10000);		// 2. change CPU clock	pxa27x_set_cpufreq(l, n2, b, t, a);	// 3. turn on LCDC clock	CKEN |= 0x110000;		//printk("********************Second*************************\n");	get_clk_frequency_khz(1);	memclk = get_memclk_frequency_10khz();	lcdclk = get_lcdclk_frequency_10khz();	printk("memclk = %d,  lcdclk = %d\n", memclk, lcdclk);		return;}/** * @brief Save the register values/status that might be changed by tvout */static void ch7013_save_lcdc(void){	g_lcdc_regs.lccr0 = LCCR0;	g_lcdc_regs.lccr1 = LCCR1;	g_lcdc_regs.lccr2 = LCCR2;	g_lcdc_regs.lccr3 = LCCR3;	g_lcdc_regs.fsadr0 = FSADR0;	g_lcdc_regs.fdadr0 = FDADR0;	g_lcdc_regs.fidr0 = FIDR0;	g_lcdc_regs.ldcmd0 = LDCMD0;	}static void ch7013_hw_init(void){	i2c_ch7013_init();		ch7013_change_cpufreq();		ch7013_set_lcdc();		mdelay(10);	ch7013_program();}static void ch7013_hw_exit(void){	i2c_ch7013_cleanup();}#if 0static void ch7013_i2c_test(void){	unsigned char chip_ver;	//silicon ID	printk("read id:\n");	i2c_ch7013_read(0x25, &chip_ver);	printk("Chip version ID(0x22)= 0x%X", chip_ver);}#endifstatic 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("PXA27x 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();		//printk("%s driver init successfully.\n",MODULE_NAME);	//ch7013_i2c_test();	//ch7013_regs_dump();		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("PXA270 TVOUT CH7013 Driver ");MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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