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

📄 cx25840-core.c

📁 trident tm5600的linux驱动
💻 C
📖 第 1 页 / 共 3 页
字号:
/* cx25840 - Conexant CX25840 audio/video decoder driver * * Copyright (C) 2004 Ulf Eklund * * Based on the saa7115 driver and on the first verison of Chris Kennedy's * cx25840 driver. * * Changes by Tyler Trafford <tatrafford@comcast.net> *    - cleanup/rewrite for V4L2 API (2005) * * VBI support by Hans Verkuil <hverkuil@xs4all.nl>. * * NTSC sliced VBI support by Christopher Neufeld <television@cneufeld.ca> * with additional fixes by Hans Verkuil <hverkuil@xs4all.nl>. * * CX23885 support by Steven Toth <stoth@linuxtv.org>. * * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. */#include <linux/kernel.h>#include <linux/module.h>#include <linux/slab.h>#include <linux/videodev2.h>#include <linux/i2c.h>#include <linux/delay.h>#include <media/v4l2-common.h>#include <media/v4l2-chip-ident.h>#include <media/v4l2-i2c-drv-legacy.h>#include <media/cx25840.h>#include "compat.h"#include "cx25840-core.h"MODULE_DESCRIPTION("Conexant CX25840 audio/video decoder driver");MODULE_AUTHOR("Ulf Eklund, Chris Kennedy, Hans Verkuil, Tyler Trafford");MODULE_LICENSE("GPL");static unsigned short normal_i2c[] = { 0x88 >> 1, I2C_CLIENT_END };static int cx25840_debug;module_param_named(debug,cx25840_debug, int, 0644);MODULE_PARM_DESC(debug, "Debugging messages [0=Off (default) 1=On]");I2C_CLIENT_INSMOD;/* ----------------------------------------------------------------------- */int cx25840_write(struct i2c_client *client, u16 addr, u8 value){	u8 buffer[3];	buffer[0] = addr >> 8;	buffer[1] = addr & 0xff;	buffer[2] = value;	return i2c_master_send(client, buffer, 3);}int cx25840_write4(struct i2c_client *client, u16 addr, u32 value){	u8 buffer[6];	buffer[0] = addr >> 8;	buffer[1] = addr & 0xff;	buffer[2] = value & 0xff;	buffer[3] = (value >> 8) & 0xff;	buffer[4] = (value >> 16) & 0xff;	buffer[5] = value >> 24;	return i2c_master_send(client, buffer, 6);}u8 cx25840_read(struct i2c_client * client, u16 addr){	u8 buffer[2];	buffer[0] = addr >> 8;	buffer[1] = addr & 0xff;	if (i2c_master_send(client, buffer, 2) < 2)		return 0;	if (i2c_master_recv(client, buffer, 1) < 1)		return 0;	return buffer[0];}u32 cx25840_read4(struct i2c_client * client, u16 addr){	u8 buffer[4];	buffer[0] = addr >> 8;	buffer[1] = addr & 0xff;	if (i2c_master_send(client, buffer, 2) < 2)		return 0;	if (i2c_master_recv(client, buffer, 4) < 4)		return 0;	return (buffer[3] << 24) | (buffer[2] << 16) |	    (buffer[1] << 8) | buffer[0];}int cx25840_and_or(struct i2c_client *client, u16 addr, unsigned and_mask,		   u8 or_value){	return cx25840_write(client, addr,			     (cx25840_read(client, addr) & and_mask) |			     or_value);}/* ----------------------------------------------------------------------- */static int set_input(struct i2c_client *client, enum cx25840_video_input vid_input,						enum cx25840_audio_input aud_input);/* ----------------------------------------------------------------------- */static void init_dll1(struct i2c_client *client){	/* This is the Hauppauge sequence used to	 * initialize the Delay Lock Loop 1 (ADC DLL). */	cx25840_write(client, 0x159, 0x23);	cx25840_write(client, 0x15a, 0x87);	cx25840_write(client, 0x15b, 0x06);	udelay(10);	cx25840_write(client, 0x159, 0xe1);	udelay(10);	cx25840_write(client, 0x15a, 0x86);	cx25840_write(client, 0x159, 0xe0);	cx25840_write(client, 0x159, 0xe1);	cx25840_write(client, 0x15b, 0x10);}static void init_dll2(struct i2c_client *client){	/* This is the Hauppauge sequence used to	 * initialize the Delay Lock Loop 2 (ADC DLL). */	cx25840_write(client, 0x15d, 0xe3);	cx25840_write(client, 0x15e, 0x86);	cx25840_write(client, 0x15f, 0x06);	udelay(10);	cx25840_write(client, 0x15d, 0xe1);	cx25840_write(client, 0x15d, 0xe0);	cx25840_write(client, 0x15d, 0xe1);}static void cx25836_initialize(struct i2c_client *client){	/* reset configuration is described on page 3-77 of the CX25836 datasheet */	/* 2. */	cx25840_and_or(client, 0x000, ~0x01, 0x01);	cx25840_and_or(client, 0x000, ~0x01, 0x00);	/* 3a. */	cx25840_and_or(client, 0x15a, ~0x70, 0x00);	/* 3b. */	cx25840_and_or(client, 0x15b, ~0x1e, 0x06);	/* 3c. */	cx25840_and_or(client, 0x159, ~0x02, 0x02);	/* 3d. */	udelay(10);	/* 3e. */	cx25840_and_or(client, 0x159, ~0x02, 0x00);	/* 3f. */	cx25840_and_or(client, 0x159, ~0xc0, 0xc0);	/* 3g. */	cx25840_and_or(client, 0x159, ~0x01, 0x00);	cx25840_and_or(client, 0x159, ~0x01, 0x01);	/* 3h. */	cx25840_and_or(client, 0x15b, ~0x1e, 0x10);}#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20)static void cx25840_work_handler(struct work_struct *work){	struct cx25840_state *state = container_of(work, struct cx25840_state, fw_work);#elsevoid cx25840_work_handler(void *arg){	struct cx25840_state *state = arg;#endif	cx25840_loadfw(state->c);	wake_up(&state->fw_wait);}static void cx25840_initialize(struct i2c_client *client){	DEFINE_WAIT(wait);	struct cx25840_state *state = i2c_get_clientdata(client);	struct workqueue_struct *q;	/* datasheet startup in numbered steps, refer to page 3-77 */	/* 2. */	cx25840_and_or(client, 0x803, ~0x10, 0x00);	/* The default of this register should be 4, but I get 0 instead.	 * Set this register to 4 manually. */	cx25840_write(client, 0x000, 0x04);	/* 3. */	init_dll1(client);	init_dll2(client);	cx25840_write(client, 0x136, 0x0a);	/* 4. */	cx25840_write(client, 0x13c, 0x01);	cx25840_write(client, 0x13c, 0x00);	/* 5. */	/* Do the firmware load in a work handler to prevent.	   Otherwise the kernel is blocked waiting for the	   bit-banging i2c interface to finish uploading the	   firmware. */#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20)	INIT_WORK(&state->fw_work, cx25840_work_handler);#else	INIT_WORK(&state->fw_work, cx25840_work_handler, state);#endif	init_waitqueue_head(&state->fw_wait);	q = create_singlethread_workqueue("cx25840_fw");	prepare_to_wait(&state->fw_wait, &wait, TASK_UNINTERRUPTIBLE);	queue_work(q, &state->fw_work);	schedule();	finish_wait(&state->fw_wait, &wait);	destroy_workqueue(q);	/* 6. */	cx25840_write(client, 0x115, 0x8c);	cx25840_write(client, 0x116, 0x07);	cx25840_write(client, 0x118, 0x02);	/* 7. */	cx25840_write(client, 0x4a5, 0x80);	cx25840_write(client, 0x4a5, 0x00);	cx25840_write(client, 0x402, 0x00);	/* 8. */	cx25840_and_or(client, 0x401, ~0x18, 0);	cx25840_and_or(client, 0x4a2, ~0x10, 0x10);	/* steps 8c and 8d are done in change_input() */	/* 10. */	cx25840_write(client, 0x8d3, 0x1f);	cx25840_write(client, 0x8e3, 0x03);	cx25840_std_setup(client);	/* trial and error says these are needed to get audio */	cx25840_write(client, 0x914, 0xa0);	cx25840_write(client, 0x918, 0xa0);	cx25840_write(client, 0x919, 0x01);	/* stereo prefered */	cx25840_write(client, 0x809, 0x04);	/* AC97 shift */	cx25840_write(client, 0x8cf, 0x0f);	/* (re)set input */	set_input(client, state->vid_input, state->aud_input);	/* start microcontroller */	cx25840_and_or(client, 0x803, ~0x10, 0x10);}static void cx23885_initialize(struct i2c_client *client){	DEFINE_WAIT(wait);	struct cx25840_state *state = i2c_get_clientdata(client);	struct workqueue_struct *q;	/* Internal Reset */	cx25840_and_or(client, 0x102, ~0x01, 0x01);	cx25840_and_or(client, 0x102, ~0x01, 0x00);	/* Stop microcontroller */	cx25840_and_or(client, 0x803, ~0x10, 0x00);	/* DIF in reset? */	cx25840_write(client, 0x398, 0);	/* Trust the default xtal, no division */	/* This changes for the cx23888 products */	cx25840_write(client, 0x2, 0x76);	/* Bring down the regulator for AUX clk */	cx25840_write(client, 0x1, 0x40);	/* Sys PLL frac */	cx25840_write4(client, 0x11c, 0x01d1744c);	/* Sys PLL int */	cx25840_write4(client, 0x118, 0x00000416);	/* Disable DIF bypass */	cx25840_write4(client, 0x33c, 0x00000001);	/* DIF Src phase inc */	cx25840_write4(client, 0x340, 0x0df7df83);	/* Vid PLL frac */	cx25840_write4(client, 0x10c, 0x01b6db7b);	/* Vid PLL int */	cx25840_write4(client, 0x108, 0x00000512);	/* Luma */	cx25840_write4(client, 0x414, 0x00107d12);	/* Chroma */	cx25840_write4(client, 0x420, 0x3d008282);	/* Aux PLL frac */	cx25840_write4(client, 0x114, 0x017dbf48);	/* Aux PLL int */	cx25840_write4(client, 0x110, 0x000a030e);	/* ADC2 input select */	cx25840_write(client, 0x102, 0x10);	/* VIN1 & VIN5 */	cx25840_write(client, 0x103, 0x11);	/* Enable format auto detect */	cx25840_write(client, 0x400, 0);#if 0	/* Force to NTSC-M and Disable autoconf regs */	cx25840_write(client, 0x400, 0x21);#endif	/* Fast subchroma lock */	/* White crush, Chroma AGC & Chroma Killer enabled */	cx25840_write(client, 0x401, 0xe8);	/* Select AFE clock pad output source */	cx25840_write(client, 0x144, 0x05);	/* Do the firmware load in a work handler to prevent.	   Otherwise the kernel is blocked waiting for the	   bit-banging i2c interface to finish uploading the	   firmware. */#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20)	INIT_WORK(&state->fw_work, cx25840_work_handler);#else	INIT_WORK(&state->fw_work, cx25840_work_handler, state);#endif	init_waitqueue_head(&state->fw_wait);	q = create_singlethread_workqueue("cx25840_fw");	prepare_to_wait(&state->fw_wait, &wait, TASK_UNINTERRUPTIBLE);	queue_work(q, &state->fw_work);	schedule();	finish_wait(&state->fw_wait, &wait);	destroy_workqueue(q);	cx25840_std_setup(client);	/* (re)set input */	set_input(client, state->vid_input, state->aud_input);	/* start microcontroller */	cx25840_and_or(client, 0x803, ~0x10, 0x10);}/* ----------------------------------------------------------------------- */void cx25840_std_setup(struct i2c_client *client){	struct cx25840_state *state = i2c_get_clientdata(client);	v4l2_std_id std = state->std;	int hblank, hactive, burst, vblank, vactive, sc;	int vblank656, src_decimation;	int luma_lpf, uv_lpf, comb;	u32 pll_int, pll_frac, pll_post;	/* datasheet startup, step 8d */	if (std & ~V4L2_STD_NTSC)		cx25840_write(client, 0x49f, 0x11);	else		cx25840_write(client, 0x49f, 0x14);	if (std & V4L2_STD_625_50) {		hblank = 132;		hactive = 720;		burst = 93;		vblank = 36;		vactive = 580;		vblank656 = 40;		src_decimation = 0x21f;		luma_lpf = 2;		if (std & V4L2_STD_SECAM) {			uv_lpf = 0;			comb = 0;			sc = 0x0a425f;		} else if (std == V4L2_STD_PAL_Nc) {			uv_lpf = 1;			comb = 0x20;			sc = 556453;		} else {			uv_lpf = 1;			comb = 0x20;			sc = 688739;		}	} else {		hactive = 720;		hblank = 122;		vactive = 487;		luma_lpf = 1;		uv_lpf = 1;		src_decimation = 0x21f;		if (std == V4L2_STD_PAL_60) {			vblank = 26;			vblank656 = 26;			burst = 0x5b;			luma_lpf = 2;			comb = 0x20;			sc = 688739;		} else if (std == V4L2_STD_PAL_M) {			vblank = 20;			vblank656 = 24;			burst = 0x61;			comb = 0x20;			sc = 555452;		} else {			vblank = 26;			vblank656 = 26;			burst = 0x5b;			comb = 0x66;			sc = 556063;		}	}	/* DEBUG: Displays configured PLL frequency */	pll_int = cx25840_read(client, 0x108);	pll_frac = cx25840_read4(client, 0x10c) & 0x1ffffff;	pll_post = cx25840_read(client, 0x109);	v4l_dbg(1, cx25840_debug, client,				"PLL regs = int: %u, frac: %u, post: %u\n",				pll_int, pll_frac, pll_post);	if (pll_post) {		int fin, fsc;		int pll = (28636363L * ((((u64)pll_int) << 25L) + pll_frac)) >> 25L;		pll /= pll_post;		v4l_dbg(1, cx25840_debug, client, "PLL = %d.%06d MHz\n",				pll / 1000000, pll % 1000000);		v4l_dbg(1, cx25840_debug, client, "PLL/8 = %d.%06d MHz\n",				pll / 8000000, (pll / 8) % 1000000);		fin = ((u64)src_decimation * pll) >> 12;		v4l_dbg(1, cx25840_debug, client,				"ADC Sampling freq = %d.%06d MHz\n",				fin / 1000000, fin % 1000000);		fsc = (((u64)sc) * pll) >> 24L;		v4l_dbg(1, cx25840_debug, client,				"Chroma sub-carrier freq = %d.%06d MHz\n",				fsc / 1000000, fsc % 1000000);		v4l_dbg(1, cx25840_debug, client, "hblank %i, hactive %i, "			"vblank %i, vactive %i, vblank656 %i, src_dec %i, "			"burst 0x%02x, luma_lpf %i, uv_lpf %i, comb 0x%02x, "			"sc 0x%06x\n",			hblank, hactive, vblank, vactive, vblank656,			src_decimation, burst, luma_lpf, uv_lpf, comb, sc);	}	/* Sets horizontal blanking delay and active lines */	cx25840_write(client, 0x470, hblank);	cx25840_write(client, 0x471,			0xff & (((hblank >> 8) & 0x3) | (hactive << 4)));	cx25840_write(client, 0x472, hactive >> 4);	/* Sets burst gate delay */	cx25840_write(client, 0x473, burst);	/* Sets vertical blanking delay and active duration */	cx25840_write(client, 0x474, vblank);	cx25840_write(client, 0x475,			0xff & (((vblank >> 8) & 0x3) | (vactive << 4)));	cx25840_write(client, 0x476, vactive >> 4);	cx25840_write(client, 0x477, vblank656);	/* Sets src decimation rate */	cx25840_write(client, 0x478, 0xff & src_decimation);	cx25840_write(client, 0x479, 0xff & (src_decimation >> 8));

⌨️ 快捷键说明

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