Mercurial > pt1.oyama
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