diff options
author | Patrick Boettcher <devnull@localhost> | 2005-01-09 15:50:44 +0000 |
---|---|---|
committer | Patrick Boettcher <devnull@localhost> | 2005-01-09 15:50:44 +0000 |
commit | ff21bded4892d260edde81df8e8f108aa229c7fc (patch) | |
tree | 8c41925392ce0aa76a48c0b973569af877414ff8 /linux/drivers/media/dvb/dibusb/dvb-dibusb-fe-i2c.c | |
parent | 9b432f78f4e082705fe90c5d8885d9f7ced755d0 (diff) | |
download | mediapointer-dvb-s2-ff21bded4892d260edde81df8e8f108aa229c7fc.tar.gz mediapointer-dvb-s2-ff21bded4892d260edde81df8e8f108aa229c7fc.tar.bz2 |
internal refactoring step 3/3
- added tuner and demod types for easier extension of new devices
- added a check for some artec devices which have another tuner
onboard, but don't know it, pll_addr is now a callback because of that
- general callbacks for pll_set, pll_init and demod_init. They decide which
pll-programming function is used and so on
- added tuner passthru callback to xfer_ops. now dibusb can en/disable the
tuner passthru of the dib3000m*-frontends; necessary for tuner probing
- remote type determination (no for hanftek, nec for others), was not planned
- fixed a bug in start_feed, which was introduced in step 2/3 but wasn't critical
- added pll-programming for lg_tdtp_e102p_tua6034 (it has the tua6034 as pll)
- added pll-programming and initialization for PANASONIC ENV77H11D5
- understood the i2c-address problem, now it is more logical
Diffstat (limited to 'linux/drivers/media/dvb/dibusb/dvb-dibusb-fe-i2c.c')
-rw-r--r-- | linux/drivers/media/dvb/dibusb/dvb-dibusb-fe-i2c.c | 363 |
1 files changed, 226 insertions, 137 deletions
diff --git a/linux/drivers/media/dvb/dibusb/dvb-dibusb-fe-i2c.c b/linux/drivers/media/dvb/dibusb/dvb-dibusb-fe-i2c.c index ee476baa1..19191a3ae 100644 --- a/linux/drivers/media/dvb/dibusb/dvb-dibusb-fe-i2c.c +++ b/linux/drivers/media/dvb/dibusb/dvb-dibusb-fe-i2c.c @@ -23,7 +23,7 @@ static int dibusb_i2c_msg(struct usb_dibusb *dib, u8 addr, len = 2 + wlen + (wo ? 0 : 2); sndbuf[0] = wo ? DIBUSB_REQ_I2C_WRITE : DIBUSB_REQ_I2C_READ; - sndbuf[1] = (addr & 0xfe) | (wo ? 0 : 1); + sndbuf[1] = (addr << 1) | (wo ? 0 : 1); memcpy(&sndbuf[2],wbuf,wlen); @@ -70,34 +70,6 @@ static u32 dibusb_i2c_func(struct i2c_adapter *adapter) return I2C_FUNC_I2C; } -int lg_tdtp_e102p_tua6034(struct dvb_frontend *fe, struct - dvb_frontend_parameters* fep, u8 *pllbuf); - -static int lg_tdtp_e102p_mt352_demod_init(struct dvb_frontend *fe) -{ - static u8 mt352_clock_config [] = { 0x89, 0xb0, 0x2d }; - static u8 mt352_reset [] = { 0x50, 0x80 }; - static u8 mt352_adc_ctl_1_cfg [] = { 0x8E, 0x40 }; - static u8 mt352_agc_cfg [] = { 0x67, 0x14, 0x22 }; - 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)); - - mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg)); - mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg)); - - return 0; -} - -static struct mt352_config lg_tdtp_e102p_tua6034_config = { - .demod_address = 0x1e, - .demod_init = lg_tdtp_e102p_mt352_demod_init, - .pll_set = lg_tdtp_e102p_tua6034, -}; - static struct i2c_algorithm dibusb_algo = { .name = "DiBcom USB i2c algorithm", .id = I2C_ALGO_BIT, @@ -105,38 +77,92 @@ static struct i2c_algorithm dibusb_algo = { .functionality = dibusb_i2c_func, }; +static int dibusb_general_demod_init(struct dvb_frontend *fe); +static u8 dibusb_general_pll_addr(struct dvb_frontend *fe); +static int dibusb_general_pll_init(struct dvb_frontend *fe, u8 pll_buf[5]); +static int dibusb_general_pll_set(struct dvb_frontend *fe, + struct dvb_frontend_parameters* params, u8 pll_buf[5]); + +static struct mt352_config mt352_hanftek_umt_010_config = { + .demod_address = 0x1e, + .demod_init = dibusb_general_demod_init, + .pll_set = dibusb_general_pll_set, +}; + +static int dibusb_tuner_quirk(struct usb_dibusb *dib) +{ + switch (dib->dibdev->dev_cl->id) { + case DIBUSB1_1_AN2235: { /* some these device have the ENV77H11D5 and some the THOMSON CABLE */ + struct dibusb_tuner *t; + u8 b[2] = { 0,0 } ,b2[1]; + struct i2c_msg msg[2] = { + { .flags = 0, .buf = b, .len = 2 }, + { .flags = I2C_M_RD, .buf = b2, .len = 1}, + }; + + t = &dibusb_tuner[DIBUSB_TUNER_COFDM_PANASONIC_ENV77H11D5]; + + msg[0].addr = (t->pll_addr << 1) | 1; + msg[1].addr = (t->pll_addr << 1) | 1; + + if (dib->xfer_ops.tuner_pass_ctrl != NULL) + dib->xfer_ops.tuner_pass_ctrl(dib->fe,1,t->pll_addr); + deb_info("ret: %d\n",dibusb_i2c_xfer(&dib->i2c_adap,msg,2)); + if (dib->xfer_ops.tuner_pass_ctrl != NULL) + dib->xfer_ops.tuner_pass_ctrl(dib->fe,0,t->pll_addr); + + if (b2[0] == 0xfe) + info("this device has the Thomson Cable onboard. Which is default."); + else { + dib->tuner = t; + info("this device has the Panasonic ENV77H11D5 onboard."); + } + break; + } + default: + break; + } + return 0; +} + int dibusb_fe_init(struct usb_dibusb* dib) { struct dib3000_config demod_cfg; int i; - if (dib->init_state & DIBUSB_STATE_I2C) - for (i = 0; i < sizeof(dib->dibdev->dev_cl->demod_i2c_addrs) / sizeof(unsigned char) && - dib->dibdev->dev_cl->demod_i2c_addrs[i] != 0; i++) { - - demod_cfg.demod_address = dib->dibdev->dev_cl->demod_i2c_addrs[i]; - demod_cfg.pll_addr = dib->dibdev->dev_cl->pll_addr; - demod_cfg.pll_set = dib->dibdev->dev_cl->pll_set; - demod_cfg.pll_init = NULL; - - switch (dib->dibdev->dev_cl->id) { - case DIBUSB1_1: - case DIBUSB1_1_AN2235: + if (dib->init_state & DIBUSB_STATE_I2C) { + for (i = 0; i < sizeof(dib->dibdev->dev_cl->demod->i2c_addrs) / sizeof(unsigned char) && + dib->dibdev->dev_cl->demod->i2c_addrs[i] != 0; i++) { + + demod_cfg.demod_address = dib->dibdev->dev_cl->demod->i2c_addrs[i]; + demod_cfg.pll_addr = dibusb_general_pll_addr; + demod_cfg.pll_set = dibusb_general_pll_set; + demod_cfg.pll_init = dibusb_general_pll_init; + + switch (dib->dibdev->dev_cl->demod->id) { + case DIBUSB_DIB3000MB: dib->fe = dib3000mb_attach(&demod_cfg,&dib->i2c_adap,&dib->xfer_ops); break; - case DIBUSB2_0: + case DIBUSB_DIB3000MC: dib->fe = dib3000mc_attach(&demod_cfg,&dib->i2c_adap,&dib->xfer_ops); break; - case UMT2_0: - dib->fe = mt352_attach(&lg_tdtp_e102p_tua6034_config, &dib->i2c_adap); + case DIBUSB_MT352: + mt352_hanftek_umt_010_config.demod_address = dib->dibdev->dev_cl->demod->i2c_addrs[i]; + dib->fe = mt352_attach(&mt352_hanftek_umt_010_config, &dib->i2c_adap); break; } if (dib->fe != NULL) { - info("found demodulator at i2c address 0x%x",demod_cfg.demod_address); + info("found demodulator at i2c address 0x%x",dib->dibdev->dev_cl->demod->i2c_addrs[i]); break; } } + + /* setting the default tuner */ + dib->tuner = dib->dibdev->dev_cl->tuner; + /* check which tuner is mounted on this device, in case this is unsure */ + dibusb_tuner_quirk(dib); + } if (dib->fe == NULL) { err("A frontend driver was not found for device '%s'.", dib->dibdev->name); @@ -160,8 +186,6 @@ int dibusb_fe_exit(struct usb_dibusb *dib) return 0; } - - int dibusb_i2c_init(struct usb_dibusb *dib) { int ret = 0; @@ -184,13 +208,6 @@ int dibusb_i2c_init(struct usb_dibusb *dib) err("could not add i2c adapter"); dib->init_state |= DIBUSB_STATE_I2C; - - u8 b[2] = { 0xff , 0xff }; - dibusb_i2c_msg(dib, 0x10, b,2, NULL, 0); - - b[0] = 0x05; - b[1] = 0x01; - dibusb_i2c_msg(dib, 0x10, b,2, NULL, 0); return ret; } @@ -204,17 +221,8 @@ int dibusb_i2c_exit(struct usb_dibusb *dib) /* pll stuff, maybe removed soon (thx to Gerd/Andrew in advance) */ -int thomson_cable_eu_pll_set(struct dvb_frontend *fe, struct - dvb_frontend_parameters *fep) +static int thomson_cable_eu_pll_set(struct dvb_frontend_parameters *fep, u8 pllbuf[4]) { - struct usb_dibusb* dib = (struct usb_dibusb*) fe->dvb->priv; - u8 buf[4]; - struct i2c_msg msg = { - .addr = dib->dibdev->dev_cl->pll_addr, - .flags = 0, - .buf = buf, - .len = sizeof(buf) - }; u32 tfreq = (fep->frequency + 36125000) / 62500; int vu,p0,p1,p2; @@ -227,33 +235,18 @@ int thomson_cable_eu_pll_set(struct dvb_frontend *fe, struct else return -EINVAL; - buf[0] = (tfreq >> 8) & 0x7f; - buf[1] = tfreq & 0xff; - buf[2] = 0x8e; - buf[3] = (vu << 7) | (p2 << 2) | (p1 << 1) | p0; - - if (i2c_transfer (&dib->i2c_adap, &msg, 1) != 1) - return -EIO; - - msleep(1); + pllbuf[0] = (tfreq >> 8) & 0x7f; + pllbuf[1] = tfreq & 0xff; + pllbuf[2] = 0x8e; + pllbuf[3] = (vu << 7) | (p2 << 2) | (p1 << 1) | p0; return 0; } -int panasonic_cofdm_env57h1xd5_pll_set(struct dvb_frontend *fe, struct - dvb_frontend_parameters *fep) +static int panasonic_cofdm_env57h1xd5_pll_set(struct dvb_frontend_parameters *fep, u8 pllbuf[4]) { - struct usb_dibusb* dib = (struct usb_dibusb*) fe->dvb->priv; - u8 buf[4]; u32 freq = fep->frequency; u32 tfreq = ((freq + 36125000)*6 + 500000) / 1000000; u8 TA, T210, R210, ctrl1, cp210, p4321; - struct i2c_msg msg = { - .addr = dib->dibdev->dev_cl->pll_addr, - .flags = 0, - .buf = buf, - .len = sizeof(buf) - }; - if (freq > 858000000) { err("frequency cannot be larger than 858 MHz."); return -EINVAL; @@ -281,15 +274,11 @@ int panasonic_cofdm_env57h1xd5_pll_set(struct dvb_frontend *fe, struct else // if (freq < 862000000) p4321 = 4; // BW selection for UHF E21 to E69 - buf[0] = (tfreq >> 8) & 0xff; - buf[1] = (tfreq >> 0) & 0xff; - buf[2] = 0xff & ctrl1; - buf[3] = (cp210 << 5) | (p4321); - - if (i2c_transfer (&dib->i2c_adap, &msg, 1) != 1) - return -EIO; + pllbuf[0] = (tfreq >> 8) & 0xff; + pllbuf[1] = (tfreq >> 0) & 0xff; + pllbuf[2] = 0xff & ctrl1; + pllbuf[3] = (cp210 << 5) | (p4321); - msleep(1); return 0; } @@ -323,26 +312,23 @@ int panasonic_cofdm_env57h1xd5_pll_set(struct dvb_frontend *fe, struct * BSn = 1 corresponding port is on */ -/* -int panasonic_cofdm_env77h11d5_tda6650_init(struct dvb_frontend *fe, u8 pllbuf[4]) -{ - +static int panasonic_cofdm_env77h11d5_tda6650_init(struct dvb_frontend *fe, u8 pllbuf[4]) +{ + pllbuf[0] = 0x0b; + pllbuf[1] = 0xf5; + pllbuf[2] = 0x85; + pllbuf[3] = 0xab; + return 0; } -*/ -/* -int panasonic_cofdm_env77h11d5_tda6650_set (struct dvb_frontend *fe, struct - dvb_frontend_parameters *fep,u8 pllbuf[4]) +static int panasonic_cofdm_env77h11d5_tda6650_set (struct dvb_frontend_parameters *fep,u8 pllbuf[4]) { - u8 tuner_buf[4]; - struct i2c_msg tuner_msg = {.addr = 0x60,.flags = 0,.buf = tuner_buf,.len = - sizeof(tuner_buf) }; int tuner_frequency = 0; u8 band, cp, filter; // determine charge pump - tuner_frequency = params->frequency + 36166000; + tuner_frequency = fep->frequency + 36166000; if (tuner_frequency < 87000000) return -EINVAL; else if (tuner_frequency < 130000000) @@ -367,46 +353,42 @@ int panasonic_cofdm_env77h11d5_tda6650_set (struct dvb_frontend *fe, struct return -EINVAL; // determine band - if (params->frequency < 49000000) + if (fep->frequency < 49000000) return -EINVAL; - else if (params->frequency < 161000000) + else if (fep->frequency < 161000000) band = 1; - else if (params->frequency < 444000000) + else if (fep->frequency < 444000000) band = 2; - else if (params->frequency < 861000000) + else if (fep->frequency < 861000000) band = 4; else return -EINVAL; // setup PLL filter - switch (params->u.ofdm.bandwidth) { - case BANDWIDTH_6_MHZ: - filter = 0; - break; - - case BANDWIDTH_7_MHZ: - filter = 0; - break; - - case BANDWIDTH_8_MHZ: - filter = 1; - break; - - default: - return -EINVAL; + switch (fep->u.ofdm.bandwidth) { + case BANDWIDTH_6_MHZ: + case BANDWIDTH_7_MHZ: + filter = 0; + break; + case BANDWIDTH_8_MHZ: + filter = 1; + break; + default: + return -EINVAL; } // calculate divisor // ((36166000+((1000000/6)/2)) + Finput)/(1000000/6) - tuner_frequency = (((params->frequency / 1000) * 6) + 217496) / 1000; + tuner_frequency = (((fep->frequency / 1000) * 6) + 217496) / 1000; // setup tuner buffer - tuner_buf[0] = (tuner_frequency >> 8) & 0x7f; - tuner_buf[1] = tuner_frequency & 0xff; - tuner_buf[2] = 0xca; - tuner_buf[3] = (cp << 5) | (filter << 3) | band; + pllbuf[0] = (tuner_frequency >> 8) & 0x7f; + pllbuf[1] = tuner_frequency & 0xff; + pllbuf[2] = 0xca; + pllbuf[3] = (cp << 5) | (filter << 3) | band; + return 0; +} -*/ /* * 7 6 5 4 3 2 1 0 * Address Byte 1 1 0 0 0 MA1 MA0 R/~W=0 @@ -430,8 +412,7 @@ int panasonic_cofdm_env77h11d5_tda6650_set (struct dvb_frontend *fe, struct * */ -int lg_tdtp_e102p_tua6034(struct dvb_frontend *fe, struct - dvb_frontend_parameters* fep, u8 *pllbuf) +static int lg_tdtp_e102p_tua6034(struct dvb_frontend_parameters* fep, u8 pllbuf[4]) { u32 div; u8 p3210, p4; @@ -442,11 +423,6 @@ int lg_tdtp_e102p_tua6034(struct dvb_frontend *fe, struct div = (fep->frequency + 36125000 + TUNER_MUL / 2) / TUNER_MUL; - pllbuf[0] = 0xc2; - pllbuf[1] = (div >> 8) & 0x7f; - pllbuf[2] = div & 0xff; - pllbuf[3] = 0xce; - if (fep->frequency < 174500000) p3210 = 1; // not supported by the tdtp_e102p else if (fep->frequency < 230000000) // VHF @@ -459,8 +435,121 @@ int lg_tdtp_e102p_tua6034(struct dvb_frontend *fe, struct else p4 = 1; - pllbuf[4] = (p4 << 4) | p3210; + pllbuf[0] = (div >> 8) & 0x7f; + pllbuf[1] = div & 0xff; + pllbuf[2] = 0xce; + pllbuf[3] = (p4 << 4) | p3210; + deb_info("pllbuf[4] = %x\n",pllbuf[4]); return 0; } + +static int lg_tdtp_e102p_mt352_demod_init(struct dvb_frontend *fe) +{ + static u8 mt352_clock_config [] = { 0x89, 0xb0, 0x2d }; + static u8 mt352_reset [] = { 0x50, 0x80 }; + static u8 mt352_adc_ctl_1_cfg [] = { 0x8E, 0x40 }; + static u8 mt352_agc_cfg [] = { 0x67, 0x14, 0x22 }; + 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)); + + mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg)); + mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg)); + + return 0; +} + +static int dibusb_general_demod_init(struct dvb_frontend *fe) +{ + struct usb_dibusb* dib = (struct usb_dibusb*) fe->dvb->priv; + switch (dib->dibdev->dev_cl->id) { + case UMT2_0: + return lg_tdtp_e102p_mt352_demod_init(fe); + default: /* other device classes do not have device specific demod inits */ + break; + } + return 0; +} + +static u8 dibusb_general_pll_addr(struct dvb_frontend *fe) +{ + struct usb_dibusb* dib = (struct usb_dibusb*) fe->dvb->priv; + return dib->tuner->pll_addr; +} + +static int dibusb_pll_i2c_helper(struct usb_dibusb *dib, u8 pll_buf[5], u8 buf[4]) +{ + if (pll_buf == NULL) { + struct i2c_msg msg = { + .addr = dib->tuner->pll_addr, + .flags = 0, + .buf = buf, + .len = sizeof(buf) + }; + if (i2c_transfer (&dib->i2c_adap, &msg, 1) != 1) + return -EIO; + msleep(1); + } else { + pll_buf[0] = dib->tuner->pll_addr << 1; + memcpy(&pll_buf[1],buf,4); + } + + return 0; +} + +static int dibusb_general_pll_init(struct dvb_frontend *fe, + u8 pll_buf[5]) +{ + struct usb_dibusb* dib = (struct usb_dibusb*) fe->dvb->priv; + u8 buf[4]; + int ret=0; + switch (dib->tuner->id) { + case DIBUSB_TUNER_COFDM_PANASONIC_ENV77H11D5: + ret = panasonic_cofdm_env77h11d5_tda6650_init(fe,buf); + break; + default: + break; + } + + if (ret) + return ret; + + return dibusb_pll_i2c_helper(dib,pll_buf,buf); +} + +static int dibusb_general_pll_set(struct dvb_frontend *fe, + struct dvb_frontend_parameters *fep, u8 pll_buf[5]) +{ + struct usb_dibusb* dib = (struct usb_dibusb*) fe->dvb->priv; + u8 buf[4]; + int ret=0; + + switch (dib->tuner->id) { + case DIBUSB_TUNER_CABLE_THOMSON: + ret = thomson_cable_eu_pll_set(fep, buf); + break; + case DIBUSB_TUNER_COFDM_PANASONIC_ENV57H1XD5: + ret = panasonic_cofdm_env57h1xd5_pll_set(fep, buf); + break; + case DIBUSB_TUNER_CABLE_LG_TDTP_E102P: + ret = lg_tdtp_e102p_tua6034(fep, buf); + break; + case DIBUSB_TUNER_COFDM_PANASONIC_ENV77H11D5: + ret = panasonic_cofdm_env77h11d5_tda6650_set(fep,buf); + break; + default: + warn("no pll programming routine found for tuner %d.\n",dib->tuner->id); + ret = -ENODEV; + break; + } + + if (ret) + return ret; + + return dibusb_pll_i2c_helper(dib,pll_buf,buf); +} |