diff options
Diffstat (limited to 'linux/drivers/media/dvb/b2c2/skystar2.c')
-rw-r--r-- | linux/drivers/media/dvb/b2c2/skystar2.c | 292 |
1 files changed, 217 insertions, 75 deletions
diff --git a/linux/drivers/media/dvb/b2c2/skystar2.c b/linux/drivers/media/dvb/b2c2/skystar2.c index 3c39ccbf7..9e7d270ea 100644 --- a/linux/drivers/media/dvb/b2c2/skystar2.c +++ b/linux/drivers/media/dvb/b2c2/skystar2.c @@ -50,6 +50,8 @@ #include "dvbdev.h" #include "demux.h" #include "dvb_net.h" +#include "stv0299.h" +#include "mt352.h" static int debug; @@ -118,10 +120,13 @@ struct adapter { int pid_count; int whole_bandwidth_count; u32 mac_filter; + + struct dvb_frontend* fe; + int (*fe_sleep)(struct dvb_frontend* fe); }; -#define write_reg_dw(adapter,reg,value) writel(value, adapter->io_mem + reg) -#define read_reg_dw(adapter,reg) readl(adapter->io_mem + reg) +#define write_reg_dw(adapter,reg,value) writel(value, (void*) (adapter->io_mem + reg)) +#define read_reg_dw(adapter,reg) readl((void*) (adapter->io_mem + reg)) static void write_reg_bitfield(struct adapter *adapter, u32 reg, u32 zeromask, u32 orvalue) { @@ -297,13 +302,6 @@ static int master_xfer(struct i2c_adapter* adapter, struct i2c_msg msgs[], int n for (i = 0; i < num; i++) { ddprintk("message %d: flags=0x%x, addr=0x%x, buf=0x%x, len=%d \n", i, msgs[i].flags, msgs[i].addr, msgs[i].buf[0], msgs[i].len); - - /* allow only the mt312, mt352 and stv0299 frontends to access the bus */ - if ((msgs[i].addr != 0x0e) && (msgs[i].addr != 0x68) && - (msgs[i].addr != 0x61) && (msgs[i].addr != 0x0f)) { - up(&tmp->i2c_sem); - return -EREMOTEIO; - } } // read command @@ -1594,7 +1592,7 @@ static void interrupt_service_dma1(struct adapter *adapter) u8 gb_tmp_buffer[188]; u8 *pb_dma_buf_cur_pos; - n_cur_dma_counter = readl(adapter->io_mem + 0x008) - adapter->dmaq1.bus_addr; + n_cur_dma_counter = readl((void*) (adapter->io_mem + 0x008)) - adapter->dmaq1.bus_addr; n_cur_dma_counter = (n_cur_dma_counter / dw_default_packet_size) * dw_default_packet_size; if ((n_cur_dma_counter < 0) || (n_cur_dma_counter > adapter->dmaq1.buffer_size)) { @@ -2170,107 +2168,250 @@ int soft_diseqc(struct adapter *adapter, unsigned int cmd, void *arg) return 0; } -static int flexcop_diseqc_ioctl(struct dvb_frontend *fe, unsigned int cmd, void *arg) +static int flexcop_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage) { - struct adapter *adapter = fe->before_after_data; + struct adapter* adapter = (struct adapter*) fe->dvb->priv; - struct dvb_frontend_info info; + dprintk("%s: FE_SET_VOLTAGE\n", __FUNCTION__); - fe->ioctl(fe, FE_GET_INFO, &info); + switch (voltage) { + case SEC_VOLTAGE_13: + dprintk("%s: SEC_VOLTAGE_13, %x\n", __FUNCTION__, SEC_VOLTAGE_13); + set_tuner_polarity(adapter, 1); + return 0; - // we must use different DiSEqC hw + case SEC_VOLTAGE_18: + dprintk("%s: SEC_VOLTAGE_18, %x\n", __FUNCTION__, SEC_VOLTAGE_18); + set_tuner_polarity(adapter, 2); + return 0; - if (strcmp(info.name, "Zarlink MT312") == 0) { - //VP310 using mt312 driver for tuning only: diseqc not wired - //use FCII instead - if (!soft_diseqc(adapter, cmd, arg)) - return 0; + default: + return -EINVAL; } +} - switch (cmd) { - case FE_SLEEP: - { - dprintk("%s: FE_SLEEP\n", __FUNCTION__); - - set_tuner_polarity(adapter, 0); +static int flexcop_sleep(struct dvb_frontend* fe) +{ + struct adapter* adapter = (struct adapter*) fe->dvb->priv; - // return -EOPNOTSUPP, to make DVB core also send "FE_SLEEP" command to frontend. - return -EOPNOTSUPP; - } + dprintk("%s: FE_SLEEP\n", __FUNCTION__); + set_tuner_polarity(adapter, 0); - case FE_SET_VOLTAGE: - { - dprintk("%s: FE_SET_VOLTAGE\n", __FUNCTION__); + if (adapter->fe_sleep) return adapter->fe_sleep(fe); + return 0; +} - switch ((fe_sec_voltage_t) arg) { - case SEC_VOLTAGE_13: +u32 flexcop_i2c_func(struct i2c_adapter *adapter) +{ + printk("flexcop_i2c_func\n"); - dprintk("%s: SEC_VOLTAGE_13, %x\n", __FUNCTION__, SEC_VOLTAGE_13); + return I2C_FUNC_I2C; +} - set_tuner_polarity(adapter, 1); +static struct i2c_algorithm flexcop_algo = { + .name = "flexcop i2c algorithm", + .id = I2C_ALGO_BIT, + .master_xfer = master_xfer, + .functionality = flexcop_i2c_func, +}; - return 0; - case SEC_VOLTAGE_18: - dprintk("%s: SEC_VOLTAGE_18, %x\n", __FUNCTION__, SEC_VOLTAGE_18); - set_tuner_polarity(adapter, 2); +static int samsung_tbmu24112_set_symbol_rate(struct dvb_frontend* fe, u32 srate, u32 ratio) +{ + u8 aclk = 0; + u8 bclk = 0; - return 0; + if (srate < 1500000) { aclk = 0xb7; bclk = 0x47; } + else if (srate < 3000000) { aclk = 0xb7; bclk = 0x4b; } + else if (srate < 7000000) { aclk = 0xb7; bclk = 0x4f; } + else if (srate < 14000000) { aclk = 0xb7; bclk = 0x53; } + else if (srate < 30000000) { aclk = 0xb6; bclk = 0x53; } + else if (srate < 45000000) { aclk = 0xb4; bclk = 0x51; } - default: + stv0299_writereg (fe, 0x13, aclk); + stv0299_writereg (fe, 0x14, bclk); + stv0299_writereg (fe, 0x1f, (ratio >> 16) & 0xff); + stv0299_writereg (fe, 0x20, (ratio >> 8) & 0xff); + stv0299_writereg (fe, 0x21, (ratio ) & 0xf0); - return -EINVAL; - }; - } + return 0; +} +static int samsung_tbmu24112_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +{ + u8 buf[4]; + u32 div; + struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) }; + struct adapter* adapter = (struct adapter*) fe->dvb->priv; - default: + div = params->frequency / 125; - return -EOPNOTSUPP; + buf[0] = (div >> 8) & 0x7f; + buf[1] = div & 0xff; + buf[2] = 0x84; // 0xC4 + buf[3] = 0x08; - }; + if (params->frequency < 1500000) buf[3] |= 0x10; + if (i2c_transfer (&adapter->i2c_adap, &msg, 1) != 1) return -EIO; return 0; } +static u8 samsung_tbmu24112_inittab[] = { + 0x01, 0x15, + 0x02, 0x00, + 0x03, 0x00, + 0x04, 0x7D, + 0x05, 0x35, + 0x06, 0x02, + 0x07, 0x00, + 0x08, 0xC3, + 0x0C, 0x00, + 0x0D, 0x81, + 0x0E, 0x23, + 0x0F, 0x12, + 0x10, 0x7E, + 0x11, 0x84, + 0x12, 0xB9, + 0x13, 0x88, + 0x14, 0x89, + 0x15, 0xC9, + 0x16, 0x00, + 0x17, 0x5C, + 0x18, 0x00, + 0x19, 0x00, + 0x1A, 0x00, + 0x1C, 0x00, + 0x1D, 0x00, + 0x1E, 0x00, + 0x1F, 0x3A, + 0x20, 0x2E, + 0x21, 0x80, + 0x22, 0xFF, + 0x23, 0xC1, + 0x28, 0x00, + 0x29, 0x1E, + 0x2A, 0x14, + 0x2B, 0x0F, + 0x2C, 0x09, + 0x2D, 0x05, + 0x31, 0x1F, + 0x32, 0x19, + 0x33, 0xFE, + 0x34, 0x93, + 0xff, 0xff, +}; + +static struct stv0299_config samsung_tbmu24112_config = { + .demod_address = 0x68, + .inittab = samsung_tbmu24112_inittab, + .mclk = 88000000UL, + .invert = 0, + .enhanced_tuning = 0, + .skip_reinit = 0, + .lock_output = STV0229_LOCKOUTPUT_LK, + .volt13_op0_op1 = STV0299_VOLT13_OP1, + .min_delay_ms = 100, + .set_symbol_rate = samsung_tbmu24112_set_symbol_rate, + .pll_set = samsung_tbmu24112_pll_set, +}; + + -static int client_register(struct i2c_client *client) + + +static int samsung_tdtc9251dh0_demod_init(struct dvb_frontend* fe) { - struct adapter *adapter = (struct adapter*)i2c_get_adapdata(client->adapter); + static u8 mt352_clock_config [] = { 0x89, 0x10, 0x2d }; + static u8 mt352_reset [] = { 0x50, 0x80 }; + static u8 mt352_adc_ctl_1_cfg [] = { 0x8E, 0x40 }; + static u8 mt352_agc_cfg [] = { 0x67, 0x28, 0xa1 }; + static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 }; + + mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config)); + udelay(2000); + mt352_write(fe, mt352_reset, sizeof(mt352_reset)); + mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg)); - dprintk("client_register\n"); + mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg)); + mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg)); - if (client->driver->command) - return client->driver->command(client, FE_REGISTER, adapter->dvb_adapter); return 0; } -static int client_unregister(struct i2c_client *client) +int samsung_tdtc9251dh0_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf) { - struct adapter *adapter = (struct adapter*)i2c_get_adapdata(client->adapter); + u32 div; + unsigned char bs = 0; + + #define IF_FREQUENCYx6 217 /* 6 * 36.16666666667MHz */ + div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6; + + if (params->frequency >= 48000000 && params->frequency <= 154000000) bs = 0x09; + if (params->frequency >= 161000000 && params->frequency <= 439000000) bs = 0x0a; + if (params->frequency >= 447000000 && params->frequency <= 863000000) bs = 0x08; - dprintk("client_unregister\n"); + pllbuf[0] = 0xc2; // Note: non-linux standard PLL i2c address + pllbuf[1] = div >> 8; + pllbuf[2] = div & 0xff; + pllbuf[3] = 0xcc; + pllbuf[4] = bs; - if (client->driver->command) - return client->driver->command(client, FE_UNREGISTER, adapter->dvb_adapter); return 0; } -u32 flexcop_i2c_func(struct i2c_adapter *adapter) +static struct mt352_config samsung_tdtc9251dh0_config = { + + .demod_address = 0x0f, + .demod_init = samsung_tdtc9251dh0_demod_init, + .pll_set = samsung_tdtc9251dh0_pll_set, +}; + + + + + +static void frontend_init(struct adapter *skystar2) { - printk("flexcop_i2c_func\n"); + switch(skystar2->pdev->device) { + case 0x2103: // Technisat Skystar2 OR Technisat Airstar2 - return I2C_FUNC_I2C; -} + // try the skystar2 first (stv0299/Samsung tbmu24112(sl1935)) + skystar2->fe = stv0299_attach(&samsung_tbmu24112_config, &skystar2->i2c_adap); + if (skystar2->fe != NULL) { + skystar2->fe->ops->set_voltage = flexcop_set_voltage; + skystar2->fe_sleep = skystar2->fe->ops->sleep; + skystar2->fe->ops->sleep = flexcop_sleep; + break; + } -static struct i2c_algorithm flexcop_algo = { - .name = "flexcop i2c algorithm", - .id = I2C_ALGO_BIT, - .master_xfer = master_xfer, - .functionality = flexcop_i2c_func, -}; + // try the airstar2 (mt352/Samsung tdtc9251dh0(??)) + skystar2->fe = mt352_attach(&samsung_tdtc9251dh0_config, &skystar2->i2c_adap); + if (skystar2->fe != NULL) { + skystar2->fe->ops->info.frequency_min = 474000000; + skystar2->fe->ops->info.frequency_max = 858000000; + break; + } + break; + } + + if (skystar2->fe == NULL) { + printk("skystar2: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n", + skystar2->pdev->vendor, + skystar2->pdev->device, + skystar2->pdev->subsystem_vendor, + skystar2->pdev->subsystem_device); + } else { + if (dvb_register_frontend(skystar2->dvb_adapter, skystar2->fe)) { + printk("skystar2: Frontend registration failed!\n"); + if (skystar2->fe->ops->release) + skystar2->fe->ops->release(skystar2->fe); + skystar2->fe = NULL; + } + } +} static int skystar2_probe(struct pci_dev *pdev, const struct pci_device_id *ent) @@ -2299,8 +2440,10 @@ static int skystar2_probe(struct pci_dev *pdev, const struct pci_device_id *ent) adapter = (struct adapter *) pci_get_drvdata(pdev); + dvb_adapter->priv = adapter; adapter->dvb_adapter = dvb_adapter; + init_MUTEX(&adapter->i2c_sem); @@ -2317,16 +2460,12 @@ static int skystar2_probe(struct pci_dev *pdev, const struct pci_device_id *ent) adapter->i2c_adap.algo = &flexcop_algo; adapter->i2c_adap.algo_data = NULL; adapter->i2c_adap.id = I2C_ALGO_BIT; - adapter->i2c_adap.client_register = client_register; - adapter->i2c_adap.client_unregister = client_unregister; if (i2c_add_adapter(&adapter->i2c_adap) < 0) { dvb_unregister_adapter (adapter->dvb_adapter); return -ENOMEM; } - dvb_add_frontend_ioctls(adapter->dvb_adapter, flexcop_diseqc_ioctl, NULL, adapter); - dvbdemux = &adapter->demux; dvbdemux->priv = (void *) adapter; @@ -2362,6 +2501,9 @@ static int skystar2_probe(struct pci_dev *pdev, const struct pci_device_id *ent) return ret; dvb_net_init(adapter->dvb_adapter, &adapter->dvbnet, &dvbdemux->dmx); + + frontend_init(adapter); + return 0; } @@ -2386,9 +2528,9 @@ static void skystar2_remove(struct pci_dev *pdev) dvb_dmxdev_release(&adapter->dmxdev); dvb_dmx_release(&adapter->demux); - if (adapter->dvb_adapter != NULL) { - dvb_remove_frontend_ioctls(adapter->dvb_adapter, flexcop_diseqc_ioctl, NULL); + if (adapter->fe != NULL) dvb_unregister_frontend(adapter->fe); + if (adapter->dvb_adapter != NULL) { i2c_del_adapter(&adapter->i2c_adap); dvb_unregister_adapter(adapter->dvb_adapter); @@ -2399,7 +2541,7 @@ static void skystar2_remove(struct pci_dev *pdev) static struct pci_device_id skystar2_pci_tbl[] = { {0x000013d0, 0x00002103, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000}, - {0x000013d0, 0x00002200, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000}, //FCIII +/* {0x000013d0, 0x00002200, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000}, UNDEFINED HARDWARE - mail linuxtv.org list */ //FCIII {0,}, }; |