Mercurial > pt1.oyama
view driver/pt1_tuner.c @ 146:066f33b2213a
EXPERIMENTAL: Select a particular program from multi-channel.
author | Naoya OYAMA <naoya.oyama@gmail.com> |
---|---|
date | Tue, 21 Aug 2012 04:21:11 +0900 |
parents | 4303bbfd5d37 |
children | 13f0666bd088 |
line wrap: on
line source
/* 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/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" 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, int cardtype, __u32 lnb, __u32 tuner) { __u32 val = TUNER_POWER_OFF; switch(lnb){ case LNB_11V: val = (1 << BIT_LNB_DOWN); break ; case LNB_15V: val = (1 << BIT_LNB_UP) | (1 << BIT_LNB_DOWN); break ; } if(cardtype == PT1) { 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 ; } } else if(cardtype == PT2) { switch(tuner){ case TUNER_POWER_ON_RESET_ENABLE: val |= (1 << BIT_TUNER) | (1 << BIT_33A1) | (1 << BIT_33A2) | (1 << BIT_5A_) | (1 << BIT_5A1) | (1 << BIT_5A2); break; case TUNER_POWER_ON_RESET_DISABLE: val |= (1 << BIT_TUNER) | (1 << BIT_RESET) | (1 << BIT_33A1) | (1 << BIT_33A2) | (1 << BIT_5A_) | (1 << BIT_5A1) | (1 << BIT_5A2); break ; } } writel(val, (regs + CFG_REGS_ADDR)); } static int init_isdb_s(void __iomem *regs, int cardtype, 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(cardtype == PT1) { if((val & 0xff) != 0x4c) { printk(KERN_INFO "PT1:ISDB-S Read(%x)\n", val); return -EIO ; } for(lp = 0 ; lp < PT1_MAX_ISDB_S_INIT ; lp++) { memcpy(&wk, isdb_s_initial_pt1[lp], sizeof(WBLOCK)); wk.addr = addr; i2c_write(regs, lock, &wk); } } else if(cardtype == PT2) { if((val & 0xff) != 0x52) { printk(KERN_INFO "PT2:ISDB-S Read(%x)\n", val); return -EIO ; } for(lp = 0 ; lp < PT2_MAX_ISDB_S_INIT ; lp++) { memcpy(&wk, isdb_s_initial_pt2[lp], sizeof(WBLOCK)); wk.addr = addr; i2c_write(regs, lock, &wk); } } return 0 ; } static void init_isdb_t(void __iomem *regs, int cardtype, struct mutex *lock, __u32 addr) { int lp ; WBLOCK wk; // ISDB-S/T初期化 if(cardtype == PT1) { for(lp = 0 ; lp < PT1_MAX_ISDB_T_INIT ; lp++){ memcpy(&wk, isdb_t_initial_pt1[lp], sizeof(WBLOCK)); wk.addr = addr; i2c_write(regs, lock, &wk); } } else if(cardtype == PT2) { for(lp = 0 ; lp < PT2_MAX_ISDB_T_INIT ; lp++){ memcpy(&wk, isdb_t_initial_pt2[lp], sizeof(WBLOCK)); wk.addr = addr; i2c_write(regs, lock, &wk); } } } int tuner_init(void __iomem *regs, int cardtype, 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, cardtype, lock, tuner_info[tuner_no].isdb_s); if(rc < 0){ return rc ; } init_isdb_t(regs, cardtype, 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: printk(KERN_INFO "PT1:ISDB-S Wakeup\n"); memcpy(&wk, &isdb_s_wake, sizeof(WBLOCK)); wk.addr = address; i2c_write(regs, lock, &wk); memcpy(&wk, &isdb_s_wake2, sizeof(WBLOCK)); wk.addr = address; i2c_write(regs, lock, &wk); break ; case CHANNEL_TYPE_ISDB_T: printk(KERN_INFO "PT1:ISDB-T Wakeup\n"); memcpy(&wk, &isdb_t_wake, sizeof(WBLOCK)); wk.addr = address; i2c_write(regs, lock, &wk); memcpy(&wk, &isdb_t_wake2, sizeof(WBLOCK)); wk.addr = address; i2c_write(regs, lock, &wk); break ; } } if(type == TYPE_SLEEP){ switch(tuner_type){ case CHANNEL_TYPE_ISDB_S: printk(KERN_INFO "PT1:ISDB-S Sleep\n"); memcpy(&wk, &isdb_s_sleep, sizeof(WBLOCK)); wk.addr = address; i2c_write(regs, lock, &wk); break ; case CHANNEL_TYPE_ISDB_T: printk(KERN_INFO "PT1:ISDB-T Sleep\n"); memcpy(&wk, &isdb_t_sleep, sizeof(WBLOCK)); wk.addr = address; i2c_write(regs, lock, &wk); break ; } } } 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_agc, 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 ; } int isdb_s_read_signal_strength(void __iomem *regs, struct mutex *lock, int addr) { WBLOCK wk; __u32 val ; __u32 val2; int val3 ; memcpy(&wk, &bs_get_signal1, sizeof(WBLOCK)); wk.addr = addr; val = i2c_read(regs, lock, &wk, 1); memcpy(&wk, &bs_get_signal2, sizeof(WBLOCK)); wk.addr = addr; val2 = i2c_read(regs, lock, &wk, 1); val3 = (((val << 8) & 0XFF00) | (val2 & 0XFF)); return val3 ; } __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; if (17 <= channel) frequencyoffset -= 2; 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 ; } int isdb_t_read_signal_strength(void __iomem *regs, struct mutex *lock, int addr) { __u32 val ; __u32 val2; __u32 val3; WBLOCK wk; memcpy(&wk, &isdb_t_signal1, 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_signal2, sizeof(WBLOCK)); wk.addr = addr; val2 = i2c_read(regs, lock, &wk, 1); val3 = (((val << 8) & 0XFF00) | (val2 & 0XFF)); return val3 ; } #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