diff driver/pt1_tuner.c @ 0:67e8eca28a80

initial import
author Yoshiki Yazawa <yaz@honeyplanet.jp>
date Mon, 16 Feb 2009 15:41:49 +0900
parents
children 07b2fc07ff48
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/driver/pt1_tuner.c	Mon Feb 16 15:41:49 2009 +0900
@@ -0,0 +1,508 @@
+/* pt1-tuner.c: A PT1 on Tuner driver for Linux. */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/mutex.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+
+#include	"pt1_com.h"
+#include	"pt1_pci.h"
+#include	"pt1_i2c.h"
+#include	"pt1_tuner.h"
+#include	"pt1_tuner_data.h"
+/*
+  LNB  : BIT 2 1
+   OFF :     0 0
+   +15V:     1 1
+   +11V:     1 0
+
+  TUNER: BIT        3 0
+   POWER-OFF      : 0 0
+   POWER-ON RESET : 0 1
+   POWER-ON ONLY  : 1 1
+*/
+typedef	struct	_TUNER_INFO{
+	int		isdb_s ;
+	int		isdb_t ;
+}TUNER_INFO;
+
+TUNER_INFO	tuner_info[2] = {
+	{T0_ISDB_S, T0_ISDB_T},
+	{T1_ISDB_S, T1_ISDB_T}
+};
+
+typedef	struct	_isdb_t_freq_add_table{
+	__u16		pos ;		// 追加するチャンネルポジション
+	__u16		add_freq ;	// 追加する値
+}isdb_t_freq_add_table;
+
+isdb_t_freq_add_table	isdb_t_freq_add[10] = {
+	{  7,  0x8081},				// 0〜7迄
+	{ 12, 0x80A1},				// 8〜12迄
+	{ 21, 0x8062},				// 13〜21迄
+	{ 39, 0x80A2},				// 22〜39迄
+	{ 51, 0x80E2},				// 40〜51迄
+	{ 59, 0x8064},				// 52〜59迄
+	{ 75, 0x8084},				// 60〜75迄
+	{ 84, 0x80a4},				// 76〜84迄
+	{100, 0x80C4},				// 85〜100迄
+	{112, 0x80E4}				// 101〜112迄
+};
+
+void	settuner_reset(void __iomem *regs, __u32 lnb, __u32 tuner)
+{
+	__u32	val = 0;
+	switch(lnb){
+		case LNB_11V: val = (1 << BIT_LNB_DOWN); break ;
+		case LNB_15V: val = (1 << BIT_LNB_UP) | (1 << BIT_LNB_DOWN) ; break ;
+	}
+
+	switch(tuner){
+		case TUNER_POWER_ON_RESET_ENABLE: val |= (1 << BIT_TUNER) ; break ;
+		case TUNER_POWER_ON_RESET_DISABLE: val = (1 << BIT_TUNER) | (1 << BIT_RESET) ; break ;
+	}
+
+	writel(val, (regs + 4));
+}
+static	int		init_isdb_s(void __iomem *regs, struct mutex *lock, __u32 addr)
+{
+
+	WBLOCK	wk;
+	int		lp ;
+	__u32	val ;
+
+	// ISDB-S/T初期化
+	memcpy(&wk, &com_initdata, sizeof(WBLOCK));
+
+	// 初期化1(なぜかREADなので)
+	memcpy(&wk, &isdb_s_init1, sizeof(WBLOCK));
+	wk.addr = addr;
+	val = i2c_read(regs, lock, &wk, 1);
+	if((val & 0xff) != 0x41){
+		printk(KERN_INFO "PT1:ISDB-S Read(%x)\n", val);
+		return -EIO ;
+	}
+	for(lp = 0 ; lp < MAX_ISDB_S_INIT ; lp++){
+		memcpy(&wk, isdb_s_initial[lp], sizeof(WBLOCK));
+		wk.addr = addr;
+		i2c_write(regs, lock, &wk);
+	}
+
+	return 0 ;
+}
+static	void	init_isdb_t(void __iomem *regs, struct mutex *lock, __u32 addr)
+{
+	int		lp ;
+	WBLOCK	wk;
+
+	// ISDB-S/T初期化
+	for(lp = 0 ; lp < MAX_ISDB_T_INIT ; lp++){
+		memcpy(&wk, isdb_t_initial[lp], sizeof(WBLOCK));
+		wk.addr = addr;
+		i2c_write(regs, lock, &wk);
+	}
+
+
+}
+int		tuner_init(void __iomem *regs, struct mutex *lock, int tuner_no)
+{
+
+	int		rc ;
+	WBLOCK	wk;
+
+	// ISDB-S/T初期化
+	memcpy(&wk, &com_initdata, sizeof(WBLOCK));
+
+	// 初期化(共通)
+	wk.addr = tuner_info[tuner_no].isdb_t ;
+	i2c_write(regs, lock, &wk);
+	wk.addr = tuner_info[tuner_no].isdb_s ;
+	i2c_write(regs, lock, &wk);
+
+	rc = init_isdb_s(regs, lock, tuner_info[tuner_no].isdb_s);
+	if(rc < 0){
+		return rc ;
+	}
+	init_isdb_t(regs, lock, tuner_info[tuner_no].isdb_t);
+
+	memcpy(&wk, &isdb_s_init21, sizeof(WBLOCK));
+	wk.addr = tuner_info[tuner_no].isdb_s ;
+	i2c_write(regs, lock, &wk);
+
+	memcpy(&wk, &isdb_t_init17, sizeof(WBLOCK));
+	wk.addr = tuner_info[tuner_no].isdb_t ;
+	i2c_write(regs, lock, &wk);
+
+	return 0 ;
+}
+void	set_sleepmode(void __iomem *regs, struct mutex *lock, int address, int tuner_type, int type)
+{
+	WBLOCK	wk;
+
+	if(type == TYPE_WAKEUP){
+		switch(tuner_type){
+			case CHANNEL_TYPE_ISDB_S:memcpy(&wk, &isdb_s_wake, sizeof(WBLOCK));break ;
+			case CHANNEL_TYPE_ISDB_T:memcpy(&wk, &isdb_t_wake, sizeof(WBLOCK));break ;
+		}
+		wk.addr = address ;
+		i2c_write(regs, lock, &wk);
+	}
+	switch(tuner_type){
+		case CHANNEL_TYPE_ISDB_S:
+			printk(KERN_INFO "PT1:ISDB-S Sleep\n");
+			memcpy(&wk, &isdb_s_sleep, sizeof(WBLOCK));
+			if(type == TYPE_WAKEUP){
+				wk.value[1] = 0x01 ;
+			}
+			break ;
+		case CHANNEL_TYPE_ISDB_T:
+			printk(KERN_INFO "PT1:ISDB-T Sleep\n");
+			memcpy(&wk, &isdb_t_sleep, sizeof(WBLOCK));
+			if(type == TYPE_WAKEUP){
+				wk.value[1] = 0x90 ;
+			}
+			break ;
+	}
+	wk.addr = address;
+	i2c_write(regs, lock, &wk);
+}
+
+int		bs_frequency(void __iomem *regs, struct mutex *lock, int addr, int channel)
+{
+	int		lp ;
+	int		tmcclock = FALSE ;
+	WBLOCK	wk;
+	__u32	val ;
+
+	if(channel >= MAX_BS_CHANNEL){
+		return -EIO ;
+	}
+	// ISDB-S PLLロック
+	for(lp = 0 ; lp < MAX_BS_CHANNEL_PLL_COMMAND ; lp++){
+		memcpy(&wk, bs_pll[channel].wblock[lp], sizeof(WBLOCK));
+		wk.addr = addr ;
+		i2c_write(regs, lock, &wk);
+	}
+
+	// PLLロック確認
+	// チェック用
+	for(lp = 0 ; lp < 200 ; lp++){
+		memcpy(&wk, &bs_pll_lock, sizeof(WBLOCK));
+		wk.addr = addr;
+		val = i2c_read(regs, lock, &wk, 1);
+		if(((val & 0xFF) != 0) && ((val & 0XFF) != 0XFF)){
+			tmcclock = TRUE ;
+			break ;
+		}
+	}
+
+	if(tmcclock == FALSE){
+		printk(KERN_INFO "PLL LOCK ERROR\n");
+		return -EIO;
+	}
+
+	memcpy(&wk, &bs_tmcc_get_1, sizeof(WBLOCK));
+	wk.addr = addr;
+	i2c_write(regs, lock, &wk);
+
+	tmcclock = FALSE ;
+
+	for(lp = 0 ; lp < 200 ; lp++){
+		memcpy(&wk, &bs_tmcc_get_2, sizeof(WBLOCK));
+		wk.addr = addr;
+
+		val = i2c_read(regs, lock, &wk, 1);
+		if(((val & 0XFF) != 0XFF) && (!(val & 0x10))){
+			tmcclock = TRUE ;
+			break ;
+		}
+	}
+
+	if(tmcclock == FALSE){
+		printk(KERN_INFO "TMCC LOCK ERROR\n");
+		return -EIO;
+	}
+
+	return 0 ;
+}
+int		ts_lock(void __iomem *regs, struct mutex *lock, int addr, __u16 ts_id)
+{
+
+	int		lp ;
+	WBLOCK	wk;
+	__u32	val ;
+	union{
+		__u8	ts[2];
+		__u16	tsid;
+	}uts_id ;
+
+	uts_id.tsid = ts_id ;
+	memcpy(&wk, &bs_set_ts_lock, sizeof(WBLOCK));
+	wk.addr = addr;
+	// TS-ID設定
+	wk.value[1]  = uts_id.ts[1];
+	wk.value[2]  = uts_id.ts[0];
+	i2c_write(regs, lock, &wk);
+
+	for(lp = 0 ; lp < 100 ; lp++){
+		memcpy(&wk, &bs_get_ts_lock, sizeof(WBLOCK));
+		wk.addr = addr;
+		val = i2c_read(regs, lock, &wk, 2);
+		if((val & 0xFFFF) == ts_id){
+			return 0 ;
+		}
+	}
+	printk(KERN_INFO "PT1:ERROR TS-LOCK(%x)\n", ts_id);
+	return -EIO ;
+}
+int		bs_tune(void __iomem *regs, struct mutex *lock, int addr, int channel, ISDB_S_TMCC *tmcc)
+{
+
+	int		lp ;
+	int		lp2;
+	WBLOCK	wk;
+	__u32	val ;
+	ISDB_S_TS_ID	*tsid ;
+	union{
+		__u8	slot[4];
+		__u32	u32slot;
+	}ts_slot ;
+	union{
+		__u16	ts[2];
+		__u32	tsid;
+	}ts_id ;
+
+	if(channel >= MAX_BS_CHANNEL){
+		printk(KERN_INFO "Invalid Channel(%d)\n", channel);
+		return -EIO ;
+	}
+	val = bs_frequency(regs, lock, addr, channel);
+	if(val == -EIO){
+		return val ;
+	}
+
+	tsid = &tmcc->ts_id[0] ;
+	// 該当周波数のTS-IDを取得
+	for(lp = 0 ; lp < (MAX_BS_TS_ID / 2) ; lp++){
+		for(lp2 = 0 ; lp2 < 100 ; lp2++){
+			memcpy(&wk, bs_get_ts_id[lp], sizeof(WBLOCK));
+			wk.addr = addr;
+			ts_id.tsid = i2c_read(regs, lock, &wk, 4);
+			// TS-IDが0の場合は再取得する
+			if((ts_id.ts[0] != 0) && (ts_id.ts[1] != 0)){
+				break ;
+			}
+		}
+		tsid->ts_id = ts_id.ts[1] ;
+		tsid += 1;
+		tsid->ts_id = ts_id.ts[0] ;
+		tsid += 1;
+	}
+
+	memcpy(&wk, &bs_get_cn, sizeof(WBLOCK));
+	wk.addr = addr;
+	tmcc->cn[0] = i2c_read(regs, lock, &wk, 1);
+
+	memcpy(&wk, &bs_get_agc, sizeof(WBLOCK));
+	wk.addr = addr;
+	tmcc->cn[1] = i2c_read(regs, lock, &wk, 1);
+
+	memcpy(&wk, &bs_get_maxagc, sizeof(WBLOCK));
+	wk.addr = addr;
+	tmcc->agc = i2c_read(regs, lock, &wk, 1);
+
+	// TS-ID別の情報を取得
+	tsid = &tmcc->ts_id[0] ;
+	for(lp = 0 ; lp < MAX_BS_TS_ID ; lp++, tsid += 1){
+		// TS-IDなし=0XFFFF
+		if(tsid->ts_id == 0xFFFF){
+			continue ;
+		}
+		ts_lock(regs, lock, addr, tsid->ts_id);
+
+		//スロット取得
+		memcpy(&wk, &bs_get_slot, sizeof(WBLOCK));
+		wk.addr = addr;
+		ts_slot.u32slot = i2c_read(regs, lock, &wk, 3);
+		tsid->high_mode = 0;
+		tsid->low_slot  = ts_slot.slot[0] ;
+		tsid->high_slot = ts_slot.slot[1] ;
+		tsid->low_mode  = ts_slot.slot[2] ;
+	}
+
+	memcpy(&wk, &bs_get_clock, sizeof(WBLOCK));
+	wk.addr = addr;
+	tmcc->clockmargin = i2c_read(regs, lock, &wk, 1);
+
+	memcpy(&wk, &bs_get_carrir, sizeof(WBLOCK));
+	wk.addr = addr;
+	tmcc->carriermargin = i2c_read(regs, lock, &wk, 1);
+	return 0 ;
+}
+__u32	getfrequency_add(__u32 channel)
+{
+	int		lp ;
+
+	for(lp = 0 ; lp < 10 ; lp++){
+		if(channel <= isdb_t_freq_add[lp].pos){
+			return isdb_t_freq_add[lp].add_freq ;
+		}
+	}
+	return 0 ;
+}
+__u32	getfrequency(__u32 channel, int addfreq)
+{
+	__u32	frequencyoffset = 0;
+	__u32	frequencyOffset = 0;
+
+	if (12 <= channel){
+		frequencyoffset += 2;
+	}else if (17 <= channel){
+		frequencyoffset = 0;
+	}else if (63 <= channel){
+		frequencyoffset += 2;
+	}
+#if 0
+	return (((93 + channel * 6 + frequencyOffset) + addfreq) * 7) + 400;
+#endif
+	frequencyOffset = 93 + channel * 6 + frequencyoffset;
+	frequencyOffset = 7 * (frequencyOffset + addfreq);
+	return frequencyOffset + 400;
+
+}
+int		isdb_t_frequency(void __iomem *regs, struct mutex *lock, int addr, int channel, int addfreq)
+{
+
+	int		lp ;
+	WBLOCK	wk;
+	__u32	val ;
+	int		tmcclock = FALSE ;
+	union{
+		__u8	charfreq[2];
+		__u16	freq;
+	}freq[2] ;
+
+	if(channel >= MAX_ISDB_T_CHANNEL){
+		return -EIO ;
+	}
+
+	freq[0].freq = getfrequency(channel, addfreq);
+	freq[1].freq = getfrequency_add(channel);
+	//指定周波数
+	memcpy(&wk, &isdb_t_pll_base, sizeof(WBLOCK));
+	wk.addr = addr ;
+	// 計算した周波数を設定
+	wk.value[wk.count] = freq[0].charfreq[1];
+	wk.count += 1 ;
+	wk.value[wk.count] = freq[0].charfreq[0];
+	wk.count += 1 ;
+
+	// 計算した周波数付加情報を設定
+	wk.value[wk.count] = freq[1].charfreq[1];
+	wk.count += 1 ;
+	wk.value[wk.count] = freq[1].charfreq[0];
+	wk.count += 1 ;
+
+	i2c_write(regs, lock, &wk);
+
+	for(lp = 0 ; lp < 100 ; lp++){
+		memcpy(&wk, &isdb_t_pll_lock, sizeof(WBLOCK));
+		wk.addr = addr;
+		val = i2c_read(regs, lock, &wk, 1);
+		if(((val & 0xFF) != 0XFF) && ((val & 0X50) == 0x50)){
+			tmcclock = TRUE ;
+			break ;
+		}
+	}
+	if(tmcclock != TRUE){
+		printk(KERN_INFO "PT1:ISDB-T LOCK NG(%08x)\n", val);
+		return -EIO ;
+	}
+
+	memcpy(&wk, &isdb_t_check_tune, sizeof(WBLOCK));
+	wk.addr = addr ;
+	i2c_write(regs, lock, &wk);
+
+	tmcclock = FALSE ;
+	for(lp = 0 ; lp < 1000 ; lp++){
+		memcpy(&wk, &isdb_t_tune_read, sizeof(WBLOCK));
+		wk.addr = addr;
+		val = i2c_read(regs, lock, &wk, 1);
+		if(((val & 0xFF) != 0XFF) && ((val & 0X8) != 8)){
+			tmcclock = TRUE ;
+			break ;
+		}
+	}
+	if(tmcclock != TRUE){
+		return -EIO ;
+	}
+	return 0 ;
+}
+#if 0
+int		isdb_t_tune(void __iomem *regs, struct mutex *lock, int addr, int channel, ISDB_T_TMCC *tmcc)
+{
+
+	int		lp ;
+	int		rc ;
+	int		lp2 ;
+	WBLOCK	wk;
+	__u32	val ;
+
+	printk(KERN_INFO "Channel(%d) Start\n", channel);
+	if(channel >= MAX_ISDB_T_CHANNEL){
+		return -EIO ;
+	}
+	rc = isdb_t_frequency(regs, lock, addr, channel);
+	if(rc < 0){
+		return -EIO ;
+	}
+	for(lp = 0 ; lp < 100 ; lp++){
+		memcpy(&wk, &isdb_t_tmcc_read_1, sizeof(WBLOCK));
+		wk.addr = addr;
+		val = i2c_read(regs, lock, &wk, 4);
+		if((val & 0xFF) != 0){
+			break ;
+		}
+	}
+	printk(KERN_INFO "TMCC(1)Val(%x)\n", val);
+
+	for(lp = 0 ; lp < 100 ; lp++){
+		memcpy(&wk, &isdb_t_tmcc_read_2, sizeof(WBLOCK));
+		wk.addr = addr;
+		val = i2c_read(regs, lock, &wk, 4);
+		if((val & 0xFF) != 0){
+			break ;
+		}
+	}
+	printk(KERN_INFO "TMCC(2)Val(%x)\n", val);
+
+	memcpy(&wk, &isdb_t_cn_1, sizeof(WBLOCK));
+	wk.addr = addr;
+	val = i2c_read(regs, lock, &wk, 1);
+	printk(KERN_INFO "CN(1)Val(%x)\n", val);
+
+	memcpy(&wk, &isdb_t_cn_2, sizeof(WBLOCK));
+	wk.addr = addr;
+	val = i2c_read(regs, lock, &wk, 1);
+	printk(KERN_INFO "CN(2)Val(%x)\n", val);
+
+	memcpy(&wk, &isdb_t_agc_1, sizeof(WBLOCK));
+	wk.addr = addr;
+	val = i2c_read(regs, lock, &wk, 1);
+	printk(KERN_INFO "AGC(1)Val(%x)\n", val);
+
+	memcpy(&wk, &isdb_t_agc_2, sizeof(WBLOCK));
+	wk.addr = addr;
+	val = i2c_read(regs, lock, &wk, 1);
+	printk(KERN_INFO "AGC(2)Val(%x)\n", val);
+	return 0;
+}
+#endif