diff options
Diffstat (limited to 'linux/drivers/media/dvb/frontends')
-rw-r--r-- | linux/drivers/media/dvb/frontends/Kconfig | 21 | ||||
-rw-r--r-- | linux/drivers/media/dvb/frontends/Makefile | 2 | ||||
-rw-r--r-- | linux/drivers/media/dvb/frontends/dvb-pll.c | 43 | ||||
-rw-r--r-- | linux/drivers/media/dvb/frontends/dvb-pll.h | 12 | ||||
-rw-r--r-- | linux/drivers/media/dvb/frontends/lgh06xf.c | 140 | ||||
-rw-r--r-- | linux/drivers/media/dvb/frontends/lgh06xf.h | 35 | ||||
-rw-r--r-- | linux/drivers/media/dvb/frontends/tda1004x.c | 89 | ||||
-rw-r--r-- | linux/drivers/media/dvb/frontends/tda1004x.h | 46 | ||||
-rw-r--r-- | linux/drivers/media/dvb/frontends/tda827x.c | 491 | ||||
-rw-r--r-- | linux/drivers/media/dvb/frontends/tda827x.h | 62 |
10 files changed, 706 insertions, 235 deletions
diff --git a/linux/drivers/media/dvb/frontends/Kconfig b/linux/drivers/media/dvb/frontends/Kconfig index 22c2cf2ce..10c4e7bdd 100644 --- a/linux/drivers/media/dvb/frontends/Kconfig +++ b/linux/drivers/media/dvb/frontends/Kconfig @@ -280,8 +280,12 @@ comment "Tuners/PLL support" depends on DVB_CORE config DVB_PLL - tristate + tristate "Generic I2C PLL based tuners" depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + This module driver a number of tuners based on PLL chips with a + common I2C interface. Say Y when you want to support these tuners. config DVB_TDA826X tristate "Philips TDA826X silicon tuner" @@ -290,6 +294,13 @@ config DVB_TDA826X help A DVB-S silicon tuner module. Say Y when you want to support this tuner. +config DVB_TDA827X + tristate "Philips TDA827X silicon tuner" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A DVB-T silicon tuner module. Say Y when you want to support this tuner. + config DVB_TUNER_QT1010 tristate "Quantek QT1010 silicon tuner" depends on DVB_CORE && I2C @@ -304,14 +315,6 @@ config DVB_TUNER_MT2060 help A driver for the silicon IF tuner MT2060 from Microtune. -config DVB_TUNER_LGH06XF - tristate "LG TDVS-H06xF ATSC tuner" - depends on DVB_CORE && I2C - select DVB_PLL - default m if DVB_FE_CUSTOMISE - help - A driver for the LG TDVS-H06xF ATSC tuner family. - comment "Miscellaneous devices" depends on DVB_CORE diff --git a/linux/drivers/media/dvb/frontends/Makefile b/linux/drivers/media/dvb/frontends/Makefile index a646d9969..905fcfc87 100644 --- a/linux/drivers/media/dvb/frontends/Makefile +++ b/linux/drivers/media/dvb/frontends/Makefile @@ -37,7 +37,7 @@ obj-$(CONFIG_DVB_LNBP21) += lnbp21.o obj-$(CONFIG_DVB_ISL6421) += isl6421.o obj-$(CONFIG_DVB_TDA10086) += tda10086.o obj-$(CONFIG_DVB_TDA826X) += tda826x.o +obj-$(CONFIG_DVB_TDA827X) += tda827x.o obj-$(CONFIG_DVB_TUNER_MT2060) += mt2060.o obj-$(CONFIG_DVB_TUNER_QT1010) += qt1010.o obj-$(CONFIG_DVB_TUA6100) += tua6100.o -obj-$(CONFIG_DVB_TUNER_LGH06XF) += lgh06xf.o diff --git a/linux/drivers/media/dvb/frontends/dvb-pll.c b/linux/drivers/media/dvb/frontends/dvb-pll.c index 62de760c8..abc08f0ae 100644 --- a/linux/drivers/media/dvb/frontends/dvb-pll.c +++ b/linux/drivers/media/dvb/frontends/dvb-pll.c @@ -27,6 +27,17 @@ /* ----------------------------------------------------------- */ /* descriptions */ +/* Set AGC TOP value to 103 dBuV: + 0x80 = Control Byte + 0x40 = 250 uA charge pump (irrelevant) + 0x18 = Aux Byte to follow + 0x06 = 64.5 kHz divider (irrelevant) + 0x01 = Disable Vt (aka sleep) + + 0x00 = AGC Time constant 2s Iagc = 300 nA (vs 0x80 = 9 nA) + 0x50 = AGC Take over point = 103 dBuV */ +static u8 tua603x_agc103[] = { 2, 0x80|0x40|0x18|0x06|0x01, 0x00|0x50 }; + struct dvb_pll_desc dvb_pll_thomson_dtt7579 = { .name = "Thomson dtt7579", .min = 177000000, @@ -113,6 +124,7 @@ struct dvb_pll_desc dvb_pll_thomson_dtt761x = { .min = 57000000, .max = 863000000, .count = 3, + .initdata = tua603x_agc103, .entries = { { 147000000, 44000000, 62500, 0x8e, 0x39 }, { 417000000, 44000000, 62500, 0x8e, 0x3a }, @@ -233,6 +245,7 @@ struct dvb_pll_desc dvb_pll_lg_tdvs_h06xf = { .name = "LG TDVS-H06xF", .min = 54000000, .max = 863000000, + .initdata = tua603x_agc103, .count = 3, .entries = { { 165000000, 44000000, 62500, 0xce, 0x01 }, @@ -599,6 +612,31 @@ static int dvb_pll_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) return 0; } +static int dvb_pll_init(struct dvb_frontend *fe) +{ + struct dvb_pll_priv *priv = fe->tuner_priv; + + if (priv->i2c == NULL) + return -EINVAL; + + if (priv->pll_desc->initdata) { + struct i2c_msg msg = { .flags = 0, + .addr = priv->pll_i2c_address, + .buf = priv->pll_desc->initdata + 1, + .len = priv->pll_desc->initdata[0] }; + + int result; + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if ((result = i2c_transfer(priv->i2c, &msg, 1)) != 1) { + return result; + } + return 0; + } + /* Shouldn't be called when initdata is NULL, maybe BUG()? */ + return -EINVAL; +} + static struct dvb_tuner_ops dvb_pll_tuner_ops = { .release = dvb_pll_release, .sleep = dvb_pll_sleep, @@ -640,9 +678,12 @@ struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, memcpy(&fe->ops.tuner_ops, &dvb_pll_tuner_ops, sizeof(struct dvb_tuner_ops)); - strncpy(fe->ops.tuner_ops.info.name, desc->name, 128); + strncpy(fe->ops.tuner_ops.info.name, desc->name, + sizeof(fe->ops.tuner_ops.info.name)); fe->ops.tuner_ops.info.frequency_min = desc->min; fe->ops.tuner_ops.info.frequency_min = desc->max; + if (desc->initdata) + fe->ops.tuner_ops.init = dvb_pll_init; fe->tuner_priv = priv; return fe; diff --git a/linux/drivers/media/dvb/frontends/dvb-pll.h b/linux/drivers/media/dvb/frontends/dvb-pll.h index 681186a5e..bb79a7815 100644 --- a/linux/drivers/media/dvb/frontends/dvb-pll.h +++ b/linux/drivers/media/dvb/frontends/dvb-pll.h @@ -13,6 +13,7 @@ struct dvb_pll_desc { u32 min; u32 max; void (*setbw)(u8 *buf, u32 freq, int bandwidth); + u8 *initdata; int count; struct { u32 limit; @@ -59,9 +60,20 @@ extern int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf, * @param desc dvb_pll_desc to use. * @return Frontend pointer on success, NULL on failure */ +#if defined(CONFIG_DVB_PLL) || (defined(CONFIG_DVB_PLL_MODULE) && defined(MODULE)) extern struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, struct i2c_adapter *i2c, struct dvb_pll_desc *desc); +#else +static inline struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, + int pll_addr, + struct i2c_adapter *i2c, + struct dvb_pll_desc *desc) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); + return NULL; +} +#endif #endif diff --git a/linux/drivers/media/dvb/frontends/lgh06xf.c b/linux/drivers/media/dvb/frontends/lgh06xf.c deleted file mode 100644 index 25396d199..000000000 --- a/linux/drivers/media/dvb/frontends/lgh06xf.c +++ /dev/null @@ -1,140 +0,0 @@ -/* - * lgh06xf.c - ATSC Tuner support for LG TDVS-H06xF - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include "dvb-pll.h" -#include "lgh06xf.h" - -#define LG_H06XF_PLL_I2C_ADDR 0x61 - -struct lgh06xf_priv { - struct i2c_adapter *i2c; - u32 frequency; -}; - -static int lgh06xf_release(struct dvb_frontend *fe) -{ - kfree(fe->tuner_priv); - fe->tuner_priv = NULL; - return 0; -} - -static int lgh06xf_set_params(struct dvb_frontend* fe, - struct dvb_frontend_parameters* params) -{ - struct lgh06xf_priv *priv = fe->tuner_priv; - u8 buf[4]; - struct i2c_msg msg = { .addr = LG_H06XF_PLL_I2C_ADDR, .flags = 0, - .buf = buf, .len = sizeof(buf) }; - u32 frequency; - int result; - - if ((result = dvb_pll_configure(&dvb_pll_lg_tdvs_h06xf, buf, - params->frequency, 0)) < 0) - return result; - else - frequency = result; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if ((result = i2c_transfer(priv->i2c, &msg, 1)) != 1) { - printk(KERN_WARNING "lgh06xf: %s error " - "(addr %02x <- %02x, result = %i)\n", - __FUNCTION__, buf[0], buf[1], result); - if (result < 0) - return result; - else - return -EREMOTEIO; - } - - /* Set the Auxiliary Byte. */ -#if 0 - buf[2] &= ~0x20; - buf[2] |= 0x18; - buf[3] = 0x50; -#else - buf[0] = buf[2]; - buf[0] &= ~0x20; - buf[0] |= 0x18; - buf[1] = 0x50; - msg.len = 2; -#endif - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if ((result = i2c_transfer(priv->i2c, &msg, 1)) != 1) { - printk(KERN_WARNING "lgh06xf: %s error " - "(addr %02x <- %02x, result = %i)\n", - __FUNCTION__, buf[0], buf[1], result); - if (result < 0) - return result; - else - return -EREMOTEIO; - } - - priv->frequency = frequency; - - return 0; -} - -static int lgh06xf_get_frequency(struct dvb_frontend *fe, u32 *frequency) -{ - struct lgh06xf_priv *priv = fe->tuner_priv; - *frequency = priv->frequency; - return 0; -} - -static struct dvb_tuner_ops lgh06xf_tuner_ops = { - .release = lgh06xf_release, - .set_params = lgh06xf_set_params, - .get_frequency = lgh06xf_get_frequency, -}; - -struct dvb_frontend* lgh06xf_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c) -{ - struct lgh06xf_priv *priv = NULL; - - priv = kzalloc(sizeof(struct lgh06xf_priv), GFP_KERNEL); - if (priv == NULL) - return NULL; - - priv->i2c = i2c; - - memcpy(&fe->ops.tuner_ops, &lgh06xf_tuner_ops, - sizeof(struct dvb_tuner_ops)); - - strlcpy(fe->ops.tuner_ops.info.name, dvb_pll_lg_tdvs_h06xf.name, - sizeof(fe->ops.tuner_ops.info.name)); - - fe->ops.tuner_ops.info.frequency_min = dvb_pll_lg_tdvs_h06xf.min; - fe->ops.tuner_ops.info.frequency_max = dvb_pll_lg_tdvs_h06xf.max; - - fe->tuner_priv = priv; - return fe; -} - -EXPORT_SYMBOL(lgh06xf_attach); - -MODULE_DESCRIPTION("LG TDVS-H06xF ATSC Tuner support"); -MODULE_AUTHOR("Michael Krufky"); -MODULE_LICENSE("GPL"); - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/linux/drivers/media/dvb/frontends/lgh06xf.h b/linux/drivers/media/dvb/frontends/lgh06xf.h deleted file mode 100644 index 510b4bedf..000000000 --- a/linux/drivers/media/dvb/frontends/lgh06xf.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * lgh06xf.h - ATSC Tuner support for LG TDVS-H06xF - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef _LGH06XF_H_ -#define _LGH06XF_H_ -#include "dvb_frontend.h" - -#if defined(CONFIG_DVB_TUNER_LGH06XF) || (defined(CONFIG_DVB_TUNER_LGH06XF_MODULE) && defined(MODULE)) -extern struct dvb_frontend* lgh06xf_attach(struct dvb_frontend* fe, - struct i2c_adapter *i2c); -#else -static inline struct dvb_frontend* lgh06xf_attach(struct dvb_frontend* fe, - struct i2c_adapter *i2c) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); - return NULL; -} -#endif /* CONFIG_DVB_TUNER_LGH06XF */ - -#endif /* _LGH06XF_H_ */ diff --git a/linux/drivers/media/dvb/frontends/tda1004x.c b/linux/drivers/media/dvb/frontends/tda1004x.c index f4a9cf9d2..f4882457d 100644 --- a/linux/drivers/media/dvb/frontends/tda1004x.c +++ b/linux/drivers/media/dvb/frontends/tda1004x.c @@ -40,20 +40,6 @@ #include "dvb_frontend.h" #include "tda1004x.h" -enum tda1004x_demod { - TDA1004X_DEMOD_TDA10045, - TDA1004X_DEMOD_TDA10046, -}; - -struct tda1004x_state { - struct i2c_adapter* i2c; - const struct tda1004x_config* config; - struct dvb_frontend frontend; - - /* private demod data */ - enum tda1004x_demod demod_type; -}; - static int debug; #define dprintk(args...) \ do { \ @@ -507,12 +493,25 @@ static int tda10046_fwupload(struct dvb_frontend* fe) tda1004x_write_byteI(state, TDA1004X_CONFC4, 0x80); } tda1004x_write_mask(state, TDA10046H_CONF_TRISTATE1, 1, 0); + /* set GPIO 1 and 3 */ + if (state->config->gpio_config != TDA10046_GPTRI) { + tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE2, 0x33); + tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0x0f, state->config->gpio_config &0x0f); + } /* let the clocks recover from sleep */ - msleep(5); + msleep(10); /* The PLLs need to be reprogrammed after sleep */ tda10046_init_plls(fe); + tda1004x_write_mask(state, TDA1004X_CONFADC2, 0xc0, 0); + + /* don't re-upload unless necessary */ + if (tda1004x_check_upload_ok(state) == 0) + return 0; + printk(KERN_INFO "tda1004x: trying to boot from eeprom\n"); + tda1004x_write_mask(state, TDA1004X_CONFC4, 4, 4); + msleep(300); /* don't re-upload unless necessary */ if (tda1004x_check_upload_ok(state) == 0) return 0; @@ -522,20 +521,23 @@ static int tda10046_fwupload(struct dvb_frontend* fe) printk(KERN_INFO "tda1004x: waiting for firmware upload...\n"); ret = state->config->request_firmware(fe, &fw, TDA10046_DEFAULT_FIRMWARE); if (ret) { - printk(KERN_ERR "tda1004x: no firmware upload (timeout or file not found?)\n"); - return ret; + /* remain compatible to old bug: try to load with tda10045 image name */ + ret = state->config->request_firmware(fe, &fw, TDA10045_DEFAULT_FIRMWARE); + if (ret) { + printk(KERN_ERR "tda1004x: no firmware upload (timeout or file not found?)\n"); + return ret; + } else { + printk(KERN_INFO "tda1004x: please rename the firmware file to %s\n", + TDA10046_DEFAULT_FIRMWARE); + } } - tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 8); // going to boot from HOST - ret = tda1004x_do_upload(state, fw->data, fw->size, TDA10046H_CODE_CPT, TDA10046H_CODE_IN); - release_firmware(fw); - if (ret) - return ret; } else { - /* boot from firmware eeprom */ - printk(KERN_INFO "tda1004x: booting from eeprom\n"); - tda1004x_write_mask(state, TDA1004X_CONFC4, 4, 4); - msleep(300); + printk(KERN_ERR "tda1004x: no request function defined, can't upload from file\n"); + return -EIO; } + tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 8); // going to boot from HOST + ret = tda1004x_do_upload(state, fw->data, fw->size, TDA10046H_CODE_CPT, TDA10046H_CODE_IN); + release_firmware(fw); return tda1004x_check_upload_ok(state); } @@ -638,37 +640,25 @@ static int tda10046_init(struct dvb_frontend* fe) switch (state->config->agc_config) { case TDA10046_AGC_DEFAULT: tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x00); // AGC setup - tda1004x_write_byteI(state, TDA10046H_CONF_POLARITY, 0x60); // set AGC polarities + tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0xf0, 0x60); // set AGC polarities break; case TDA10046_AGC_IFO_AUTO_NEG: tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x0a); // AGC setup - tda1004x_write_byteI(state, TDA10046H_CONF_POLARITY, 0x60); // set AGC polarities + tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0xf0, 0x60); // set AGC polarities break; case TDA10046_AGC_IFO_AUTO_POS: tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x0a); // AGC setup - tda1004x_write_byteI(state, TDA10046H_CONF_POLARITY, 0x00); // set AGC polarities - break; - case TDA10046_AGC_TDA827X_GP11: - tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x02); // AGC setup - tda1004x_write_byteI(state, TDA10046H_AGC_THR, 0x70); // AGC Threshold - tda1004x_write_byteI(state, TDA10046H_AGC_RENORM, 0x08); // Gain Renormalize - tda1004x_write_byteI(state, TDA10046H_CONF_POLARITY, 0x6a); // set AGC polarities + tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0xf0, 0x00); // set AGC polarities break; - case TDA10046_AGC_TDA827X_GP00: + case TDA10046_AGC_TDA827X: tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x02); // AGC setup tda1004x_write_byteI(state, TDA10046H_AGC_THR, 0x70); // AGC Threshold tda1004x_write_byteI(state, TDA10046H_AGC_RENORM, 0x08); // Gain Renormalize - tda1004x_write_byteI(state, TDA10046H_CONF_POLARITY, 0x60); // set AGC polarities - break; - case TDA10046_AGC_TDA827X_GP01: - tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x02); // AGC setup - tda1004x_write_byteI(state, TDA10046H_AGC_THR, 0x70); // AGC Threshold - tda1004x_write_byteI(state, TDA10046H_AGC_RENORM, 0x08); // Gain Renormalize - tda1004x_write_byteI(state, TDA10046H_CONF_POLARITY, 0x62); // set AGC polarities + tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0xf0, 0x60); // set AGC polarities break; } tda1004x_write_byteI(state, TDA1004X_CONFADC2, 0x38); - tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE1, 0x61); // Turn both AGC outputs on + tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE1, 0x79); // Turn IF AGC output on tda1004x_write_byteI(state, TDA10046H_AGC_TUN_MIN, 0); // } tda1004x_write_byteI(state, TDA10046H_AGC_TUN_MAX, 0xff); // } AGC min/max values tda1004x_write_byteI(state, TDA10046H_AGC_IF_MIN, 0); // } @@ -705,7 +695,8 @@ static int tda1004x_set_fe(struct dvb_frontend* fe, // set frequency if (fe->ops.tuner_ops.set_params) { fe->ops.tuner_ops.set_params(fe, fe_params); - if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); } // Hardcoded to use auto as much as possible on the TDA10045 as it @@ -1165,6 +1156,7 @@ static int tda1004x_read_ber(struct dvb_frontend* fe, u32* ber) static int tda1004x_sleep(struct dvb_frontend* fe) { struct tda1004x_state* state = fe->demodulator_priv; + int gpio_conf; switch (state->demod_type) { case TDA1004X_DEMOD_TDA10045: @@ -1174,6 +1166,13 @@ static int tda1004x_sleep(struct dvb_frontend* fe) case TDA1004X_DEMOD_TDA10046: /* set outputs to tristate */ tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE1, 0xff); + /* invert GPIO 1 and 3 if desired*/ + gpio_conf = state->config->gpio_config; + if (gpio_conf >= TDA10046_GP00_I) + tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0x0f, + (gpio_conf & 0x0f) ^ 0x0a); + + tda1004x_write_mask(state, TDA1004X_CONFADC2, 0xc0, 0xc0); tda1004x_write_mask(state, TDA1004X_CONFC4, 1, 1); break; } diff --git a/linux/drivers/media/dvb/frontends/tda1004x.h b/linux/drivers/media/dvb/frontends/tda1004x.h index ec502d71b..6badc81d4 100644 --- a/linux/drivers/media/dvb/frontends/tda1004x.h +++ b/linux/drivers/media/dvb/frontends/tda1004x.h @@ -35,9 +35,23 @@ enum tda10046_agc { TDA10046_AGC_DEFAULT, /* original configuration */ TDA10046_AGC_IFO_AUTO_NEG, /* IF AGC only, automatic, negtive */ TDA10046_AGC_IFO_AUTO_POS, /* IF AGC only, automatic, positive */ - TDA10046_AGC_TDA827X_GP11, /* IF AGC only, special setup for tda827x */ - TDA10046_AGC_TDA827X_GP00, /* same as above, but GPIOs 0 */ - TDA10046_AGC_TDA827X_GP01, /* same as above, but GPIO3=0 GPIO1=1*/ + TDA10046_AGC_TDA827X, /* IF AGC only, special setup for tda827x */ +}; + +/* Many (hybrid) boards use GPIO 1 and 3 + GPIO1 analog - dvb switch + GPIO3 firmware eeprom address switch +*/ +enum tda10046_gpio { + TDA10046_GPTRI = 0x00, /* All GPIOs tristate */ + TDA10046_GP00 = 0x40, /* GPIO3=0, GPIO1=0 */ + TDA10046_GP01 = 0x42, /* GPIO3=0, GPIO1=1 */ + TDA10046_GP10 = 0x48, /* GPIO3=1, GPIO1=0 */ + TDA10046_GP11 = 0x4a, /* GPIO3=1, GPIO1=1 */ + TDA10046_GP00_I = 0x80, /* GPIO3=0, GPIO1=0, invert in sleep mode*/ + TDA10046_GP01_I = 0x82, /* GPIO3=0, GPIO1=1, invert in sleep mode */ + TDA10046_GP10_I = 0x88, /* GPIO3=1, GPIO1=0, invert in sleep mode */ + TDA10046_GP11_I = 0x8a, /* GPIO3=1, GPIO1=1, invert in sleep mode */ }; enum tda10046_if { @@ -67,11 +81,35 @@ struct tda1004x_config /* AGC configuration */ enum tda10046_agc agc_config; + /* setting of GPIO1 and 3 */ + enum tda10046_gpio gpio_config; + + /* slave address and configuration of the tuner */ + u8 tuner_address; + u8 tuner_config; + u8 antenna_switch; + + /* if the board uses another I2c Bridge (tda8290), its address */ + u8 i2c_gate; + /* request firmware for device */ - /* set this to NULL if the card has a firmware EEPROM */ int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name); }; +enum tda1004x_demod { + TDA1004X_DEMOD_TDA10045, + TDA1004X_DEMOD_TDA10046, +}; + +struct tda1004x_state { + struct i2c_adapter* i2c; + const struct tda1004x_config* config; + struct dvb_frontend frontend; + + /* private demod data */ + enum tda1004x_demod demod_type; +}; + #if defined(CONFIG_DVB_TDA1004X) || (defined(CONFIG_DVB_TDA1004X_MODULE) && defined(MODULE)) extern struct dvb_frontend* tda10045_attach(const struct tda1004x_config* config, struct i2c_adapter* i2c); diff --git a/linux/drivers/media/dvb/frontends/tda827x.c b/linux/drivers/media/dvb/frontends/tda827x.c new file mode 100644 index 000000000..8176a9b58 --- /dev/null +++ b/linux/drivers/media/dvb/frontends/tda827x.c @@ -0,0 +1,491 @@ +/* + * + * (c) 2005 Hartmut Hackmann + * (c) 2007 Michael Krufky + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <linux/module.h> +#include <linux/dvb/frontend.h> +#include <asm/types.h> + +#include "tda827x.h" + +static int debug = 0; +#define dprintk(args...) \ + do { \ + if (debug) printk(KERN_DEBUG "tda827x: " args); \ + } while (0) + +struct tda827x_priv { + int i2c_addr; + struct i2c_adapter *i2c_adap; + struct tda827x_config *cfg; + u32 frequency; + u32 bandwidth; +}; + +struct tda827x_data { + u32 lomax; + u8 spd; + u8 bs; + u8 bp; + u8 cp; + u8 gc3; + u8 div1p5; +}; + +static const struct tda827x_data tda827x_dvbt[] = { + { .lomax = 62000000, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1}, + { .lomax = 66000000, .spd = 3, .bs = 3, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1}, + { .lomax = 76000000, .spd = 3, .bs = 1, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 0}, + { .lomax = 84000000, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 0}, + { .lomax = 93000000, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 1, .div1p5 = 0}, + { .lomax = 98000000, .spd = 3, .bs = 3, .bp = 0, .cp = 0, .gc3 = 1, .div1p5 = 0}, + { .lomax = 109000000, .spd = 3, .bs = 3, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0}, + { .lomax = 123000000, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 1}, + { .lomax = 133000000, .spd = 2, .bs = 3, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 1}, + { .lomax = 151000000, .spd = 2, .bs = 1, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0}, + { .lomax = 154000000, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0}, + { .lomax = 181000000, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 0, .div1p5 = 0}, + { .lomax = 185000000, .spd = 2, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, + { .lomax = 217000000, .spd = 2, .bs = 3, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, + { .lomax = 244000000, .spd = 1, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 1}, + { .lomax = 265000000, .spd = 1, .bs = 3, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 1}, + { .lomax = 302000000, .spd = 1, .bs = 1, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, + { .lomax = 324000000, .spd = 1, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, + { .lomax = 370000000, .spd = 1, .bs = 2, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0}, + { .lomax = 454000000, .spd = 1, .bs = 3, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0}, + { .lomax = 493000000, .spd = 0, .bs = 2, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 1}, + { .lomax = 530000000, .spd = 0, .bs = 3, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 1}, + { .lomax = 554000000, .spd = 0, .bs = 1, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0}, + { .lomax = 604000000, .spd = 0, .bs = 1, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0}, + { .lomax = 696000000, .spd = 0, .bs = 2, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0}, + { .lomax = 740000000, .spd = 0, .bs = 2, .bp = 4, .cp = 1, .gc3 = 0, .div1p5 = 0}, + { .lomax = 820000000, .spd = 0, .bs = 3, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0}, + { .lomax = 865000000, .spd = 0, .bs = 3, .bp = 4, .cp = 1, .gc3 = 0, .div1p5 = 0}, + { .lomax = 0, .spd = 0, .bs = 0, .bp = 0, .cp = 0, .gc3 = 0, .div1p5 = 0} +}; + +static int tda827xo_set_params(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params) +{ + struct tda827x_priv *priv = fe->tuner_priv; + u8 buf[14]; + + struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0, + .buf = buf, .len = sizeof(buf) }; + int i, tuner_freq, if_freq; + u32 N; + + switch (params->u.ofdm.bandwidth) { + case BANDWIDTH_6_MHZ: + if_freq = 4000000; + break; + case BANDWIDTH_7_MHZ: + if_freq = 4500000; + break; + default: /* 8 MHz or Auto */ + if_freq = 5000000; + break; + } + tuner_freq = params->frequency + if_freq; + + i = 0; + while (tda827x_dvbt[i].lomax < tuner_freq) { + if(tda827x_dvbt[i + 1].lomax == 0) + break; + i++; + } + + N = ((tuner_freq + 125000) / 250000) << (tda827x_dvbt[i].spd + 2); + buf[0] = 0; + buf[1] = (N>>8) | 0x40; + buf[2] = N & 0xff; + buf[3] = 0; + buf[4] = 0x52; + buf[5] = (tda827x_dvbt[i].spd << 6) + (tda827x_dvbt[i].div1p5 << 5) + + (tda827x_dvbt[i].bs << 3) + tda827x_dvbt[i].bp; + buf[6] = (tda827x_dvbt[i].gc3 << 4) + 0x8f; + buf[7] = 0xbf; + buf[8] = 0x2a; + buf[9] = 0x05; + buf[10] = 0xff; + buf[11] = 0x00; + buf[12] = 0x00; + buf[13] = 0x40; + + msg.len = 14; + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer(priv->i2c_adap, &msg, 1) != 1) { + printk("%s: could not write to tuner at addr: 0x%02x\n", + __FUNCTION__, priv->i2c_addr << 1); + return -EIO; + } + msleep(500); + /* correct CP value */ + buf[0] = 0x30; + buf[1] = 0x50 + tda827x_dvbt[i].cp; + msg.len = 2; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + i2c_transfer(priv->i2c_adap, &msg, 1); + + priv->frequency = tuner_freq - if_freq; // FIXME + priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0; + + return 0; +} + +static int tda827xo_sleep(struct dvb_frontend *fe) +{ + struct tda827x_priv *priv = fe->tuner_priv; + static u8 buf[] = { 0x30, 0xd0 }; + struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0, + .buf = buf, .len = sizeof(buf) }; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + i2c_transfer(priv->i2c_adap, &msg, 1); + + if (priv->cfg && priv->cfg->sleep) + priv->cfg->sleep(fe); + + return 0; +} + +/* ------------------------------------------------------------------ */ + +struct tda827xa_data { + u32 lomax; + u8 svco; + u8 spd; + u8 scr; + u8 sbs; + u8 gc3; +}; + +static const struct tda827xa_data tda827xa_dvbt[] = { + { .lomax = 56875000, .svco = 3, .spd = 4, .scr = 0, .sbs = 0, .gc3 = 1}, + { .lomax = 67250000, .svco = 0, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 1}, + { .lomax = 81250000, .svco = 1, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 1}, + { .lomax = 97500000, .svco = 2, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 1}, + { .lomax = 113750000, .svco = 3, .spd = 3, .scr = 0, .sbs = 1, .gc3 = 1}, + { .lomax = 134500000, .svco = 0, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, + { .lomax = 154000000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, + { .lomax = 162500000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, + { .lomax = 183000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, + { .lomax = 195000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1}, + { .lomax = 227500000, .svco = 3, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1}, + { .lomax = 269000000, .svco = 0, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1}, + { .lomax = 290000000, .svco = 1, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1}, + { .lomax = 325000000, .svco = 1, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 1}, + { .lomax = 390000000, .svco = 2, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 1}, + { .lomax = 455000000, .svco = 3, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 1}, + { .lomax = 520000000, .svco = 0, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1}, + { .lomax = 538000000, .svco = 0, .spd = 0, .scr = 1, .sbs = 3, .gc3 = 1}, + { .lomax = 550000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1}, + { .lomax = 620000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, + { .lomax = 650000000, .svco = 1, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, + { .lomax = 700000000, .svco = 2, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, + { .lomax = 780000000, .svco = 2, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, + { .lomax = 820000000, .svco = 3, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, + { .lomax = 870000000, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, + { .lomax = 911000000, .svco = 3, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 0}, + { .lomax = 0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0} +}; + +static int tda827xa_set_params(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params) +{ + struct tda827x_priv *priv = fe->tuner_priv; + u8 buf[11]; + + struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0, + .buf = buf, .len = sizeof(buf) }; + + int i, tuner_freq, if_freq; + u32 N; + + if (priv->cfg && priv->cfg->lna_gain) + priv->cfg->lna_gain(fe, 1); + msleep(20); + + switch (params->u.ofdm.bandwidth) { + case BANDWIDTH_6_MHZ: + if_freq = 4000000; + break; + case BANDWIDTH_7_MHZ: + if_freq = 4500000; + break; + default: /* 8 MHz or Auto */ + if_freq = 5000000; + break; + } + tuner_freq = params->frequency + if_freq; + + i = 0; + while (tda827xa_dvbt[i].lomax < tuner_freq) { + if(tda827xa_dvbt[i + 1].lomax == 0) + break; + i++; + } + + N = ((tuner_freq + 31250) / 62500) << tda827xa_dvbt[i].spd; + buf[0] = 0; // subaddress + buf[1] = N >> 8; + buf[2] = N & 0xff; + buf[3] = 0; + buf[4] = 0x16; + buf[5] = (tda827xa_dvbt[i].spd << 5) + (tda827xa_dvbt[i].svco << 3) + + tda827xa_dvbt[i].sbs; + buf[6] = 0x4b + (tda827xa_dvbt[i].gc3 << 4); + buf[7] = 0x1c; + buf[8] = 0x06; + buf[9] = 0x24; + buf[10] = 0x00; + msg.len = 11; + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer(priv->i2c_adap, &msg, 1) != 1) { + printk("%s: could not write to tuner at addr: 0x%02x\n", + __FUNCTION__, priv->i2c_addr << 1); + return -EIO; + } + buf[0] = 0x90; + buf[1] = 0xff; + buf[2] = 0x60; + buf[3] = 0x00; + buf[4] = 0x59; // lpsel, for 6MHz + 2 + msg.len = 5; + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + i2c_transfer(priv->i2c_adap, &msg, 1); + + buf[0] = 0xa0; + buf[1] = 0x40; + msg.len = 2; + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + i2c_transfer(priv->i2c_adap, &msg, 1); + + msleep(11); + msg.flags = I2C_M_RD; + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + i2c_transfer(priv->i2c_adap, &msg, 1); + msg.flags = 0; + + buf[1] >>= 4; + dprintk("tda8275a AGC2 gain is: %d\n", buf[1]); + if ((buf[1]) < 2) { + if (priv->cfg && priv->cfg->lna_gain) + priv->cfg->lna_gain(fe, 0); + buf[0] = 0x60; + buf[1] = 0x0c; + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + i2c_transfer(priv->i2c_adap, &msg, 1); + } + + buf[0] = 0xc0; + buf[1] = 0x99; // lpsel, for 6MHz + 2 + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + i2c_transfer(priv->i2c_adap, &msg, 1); + + buf[0] = 0x60; + buf[1] = 0x3c; + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + i2c_transfer(priv->i2c_adap, &msg, 1); + + /* correct CP value */ + buf[0] = 0x30; + buf[1] = 0x10 + tda827xa_dvbt[i].scr; + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + i2c_transfer(priv->i2c_adap, &msg, 1); + + msleep(163); + buf[0] = 0xc0; + buf[1] = 0x39; // lpsel, for 6MHz + 2 + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + i2c_transfer(priv->i2c_adap, &msg, 1); + + msleep(3); + /* freeze AGC1 */ + buf[0] = 0x50; + buf[1] = 0x4f + (tda827xa_dvbt[i].gc3 << 4); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + i2c_transfer(priv->i2c_adap, &msg, 1); + + priv->frequency = tuner_freq - if_freq; // FIXME + priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0; + + return 0; +} + +static int tda827xa_sleep(struct dvb_frontend *fe) +{ + struct tda827x_priv *priv = fe->tuner_priv; + static u8 buf[] = { 0x30, 0x90 }; + struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0, + .buf = buf, .len = sizeof(buf) }; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + i2c_transfer(priv->i2c_adap, &msg, 1); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + if (priv->cfg && priv->cfg->sleep) + priv->cfg->sleep(fe); + + return 0; +} + +static int tda827x_release(struct dvb_frontend *fe) +{ + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; + return 0; +} + +static int tda827x_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct tda827x_priv *priv = fe->tuner_priv; + *frequency = priv->frequency; + return 0; +} + +static int tda827x_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) +{ + struct tda827x_priv *priv = fe->tuner_priv; + *bandwidth = priv->bandwidth; + return 0; +} + +static int tda827x_init(struct dvb_frontend *fe) +{ + struct tda827x_priv *priv = fe->tuner_priv; + + if (priv->cfg && priv->cfg->init) + priv->cfg->init(fe); + + return 0; +} + + +static struct dvb_tuner_ops tda827xo_tuner_ops = { + .info = { + .name = "Philips TDA827X", + .frequency_min = 55000000, + .frequency_max = 860000000, + .frequency_step = 250000 + }, + .release = tda827x_release, + .init = tda827x_init, + .sleep = tda827xo_sleep, + .set_params = tda827xo_set_params, + .get_frequency = tda827x_get_frequency, + .get_bandwidth = tda827x_get_bandwidth, +}; + +static struct dvb_tuner_ops tda827xa_tuner_ops = { + .info = { + .name = "Philips TDA827XA", + .frequency_min = 44000000, + .frequency_max = 906000000, + .frequency_step = 62500 + }, + .release = tda827x_release, + .init = tda827x_init, + .sleep = tda827xa_sleep, + .set_params = tda827xa_set_params, + .get_frequency = tda827x_get_frequency, + .get_bandwidth = tda827x_get_bandwidth, +}; + +struct dvb_frontend *tda827x_attach(struct dvb_frontend *fe, int addr, + struct i2c_adapter *i2c, + struct tda827x_config *cfg) +{ + struct tda827x_priv *priv = NULL; + u8 data; + u8 sb_msg[] = { 0x30, 0xd0 }; + struct i2c_msg msg = { .addr = addr, .flags = I2C_M_RD, + .buf = &data, .len = 1 }; + dprintk("%s:\n", __FUNCTION__); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + if (i2c_transfer(i2c, &msg, 1) != 1) { + printk("%s: could not read from tuner at addr: 0x%02x\n", + __FUNCTION__, addr << 1); + return NULL; + } + + priv = kzalloc(sizeof(struct tda827x_priv), GFP_KERNEL); + if (priv == NULL) + return NULL; + + priv->i2c_addr = addr; + priv->i2c_adap = i2c; + priv->cfg = cfg; + + msg.flags = 0; + msg.buf = sb_msg; + msg.len = sizeof(sb_msg); + + if ((data & 0x3c) == 0) { + dprintk("tda827x tuner found\n"); + memcpy(&fe->ops.tuner_ops, &tda827xo_tuner_ops, sizeof(struct dvb_tuner_ops)); + } else { + dprintk("tda827xa tuner found\n"); + memcpy(&fe->ops.tuner_ops, &tda827xa_tuner_ops, sizeof(struct dvb_tuner_ops)); + sb_msg[1] = 0x90; + } + fe->tuner_priv = priv; + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + i2c_transfer(i2c, &msg, 1); + return fe; +} +EXPORT_SYMBOL(tda827x_attach); + +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); + +MODULE_DESCRIPTION("DVB TDA827x driver"); +MODULE_AUTHOR("Hartmut Hackmann <hartmut.hackmann@t-online.de>"); +MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>"); +MODULE_LICENSE("GPL"); + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/linux/drivers/media/dvb/frontends/tda827x.h b/linux/drivers/media/dvb/frontends/tda827x.h new file mode 100644 index 000000000..69e8263d6 --- /dev/null +++ b/linux/drivers/media/dvb/frontends/tda827x.h @@ -0,0 +1,62 @@ + /* + DVB Driver for Philips tda827x / tda827xa Silicon tuners + + (c) 2005 Hartmut Hackmann + (c) 2007 Michael Krufky + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + */ + +#ifndef __DVB_TDA827X_H__ +#define __DVB_TDA827X_H__ + +#include <linux/i2c.h> +#include "dvb_frontend.h" + +struct tda827x_config +{ + void (*lna_gain) (struct dvb_frontend *fe, int high); + int (*init) (struct dvb_frontend *fe); + int (*sleep) (struct dvb_frontend *fe); +}; + + +/** + * Attach a tda827x tuner to the supplied frontend structure. + * + * @param fe Frontend to attach to. + * @param addr i2c address of the tuner. + * @param i2c i2c adapter to use. + * @param cfg optional callback function pointers. + * @return FE pointer on success, NULL on failure. + */ +#if defined(CONFIG_DVB_TDA827X) || (defined(CONFIG_DVB_TDA827X_MODULE) && defined(MODULE)) +extern struct dvb_frontend* tda827x_attach(struct dvb_frontend *fe, int addr, + struct i2c_adapter *i2c, + struct tda827x_config *cfg); +#else +static inline struct dvb_frontend* tda827x_attach(struct dvb_frontend *fe, + int addr, + struct i2c_adapter *i2c, + struct tda827x_config *cfg) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); + return NULL; +} +#endif // CONFIG_DVB_TDA827X + +#endif // __DVB_TDA827X_H__ |