diff options
author | Paul Mackerras <paulus@samba.org> | 2007-04-30 12:38:01 +1000 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2007-04-30 12:38:01 +1000 |
commit | 49e1900d4cc2e7bcecb681fe60f0990bec2dcce8 (patch) | |
tree | 253801ebf57e0a23856a2c7be129c2c178f62fdf /drivers/media/dvb/frontends | |
parent | 34f6d749c0a328817d5e36274e53121c1db734dc (diff) | |
parent | b9099ff63c75216d6ca10bce5a1abcd9293c27e6 (diff) | |
download | blackbird-obmc-linux-49e1900d4cc2e7bcecb681fe60f0990bec2dcce8.tar.gz blackbird-obmc-linux-49e1900d4cc2e7bcecb681fe60f0990bec2dcce8.zip |
Merge branch 'linux-2.6' into for-2.6.22
Diffstat (limited to 'drivers/media/dvb/frontends')
-rw-r--r-- | drivers/media/dvb/frontends/Kconfig | 28 | ||||
-rw-r--r-- | drivers/media/dvb/frontends/Makefile | 3 | ||||
-rw-r--r-- | drivers/media/dvb/frontends/dvb-pll.c | 340 | ||||
-rw-r--r-- | drivers/media/dvb/frontends/dvb-pll.h | 16 | ||||
-rw-r--r-- | drivers/media/dvb/frontends/lgdt330x.c | 4 | ||||
-rw-r--r-- | drivers/media/dvb/frontends/lgh06xf.c | 134 | ||||
-rw-r--r-- | drivers/media/dvb/frontends/lgh06xf.h | 35 | ||||
-rw-r--r-- | drivers/media/dvb/frontends/or51132.c | 305 | ||||
-rw-r--r-- | drivers/media/dvb/frontends/tda10021.c | 47 | ||||
-rw-r--r-- | drivers/media/dvb/frontends/tda10023.c | 540 | ||||
-rw-r--r-- | drivers/media/dvb/frontends/tda1002x.h (renamed from drivers/media/dvb/frontends/tda10021.h) | 33 | ||||
-rw-r--r-- | drivers/media/dvb/frontends/tda1004x.c | 98 | ||||
-rw-r--r-- | drivers/media/dvb/frontends/tda1004x.h | 54 | ||||
-rw-r--r-- | drivers/media/dvb/frontends/tda827x.c | 512 | ||||
-rw-r--r-- | drivers/media/dvb/frontends/tda827x.h | 62 |
15 files changed, 1632 insertions, 579 deletions
diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig index 22c2cf2cea98..ff448761dcef 100644 --- a/drivers/media/dvb/frontends/Kconfig +++ b/drivers/media/dvb/frontends/Kconfig @@ -205,6 +205,13 @@ config DVB_TDA10021 help A DVB-C tuner module. Say Y when you want to support this frontend. +config DVB_TDA10023 + tristate "Philips TDA10023 based" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A DVB-C tuner module. Say Y when you want to support this frontend. + config DVB_STV0297 tristate "ST STV0297 based" depends on DVB_CORE && I2C @@ -280,8 +287,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 +301,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 +322,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/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile index a646d9969b71..27f386585d43 100644 --- a/drivers/media/dvb/frontends/Makefile +++ b/drivers/media/dvb/frontends/Makefile @@ -25,6 +25,7 @@ obj-$(CONFIG_DVB_MT352) += mt352.o obj-$(CONFIG_DVB_ZL10353) += zl10353.o obj-$(CONFIG_DVB_CX22702) += cx22702.o obj-$(CONFIG_DVB_TDA10021) += tda10021.o +obj-$(CONFIG_DVB_TDA10023) += tda10023.o obj-$(CONFIG_DVB_STV0297) += stv0297.o obj-$(CONFIG_DVB_NXT200X) += nxt200x.o obj-$(CONFIG_DVB_OR51211) += or51211.o @@ -37,7 +38,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/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c index 62de760c844f..5f96ffda91ad 100644 --- a/drivers/media/dvb/frontends/dvb-pll.c +++ b/drivers/media/dvb/frontends/dvb-pll.c @@ -27,17 +27,29 @@ /* ----------------------------------------------------------- */ /* 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, .max = 858000000, - .count = 5, + .iffreq= 36166667, + .sleepdata = (u8[]){ 2, 0xb4, 0x03 }, + .count = 4, .entries = { - { 0, 36166667, 166666, 0xb4, 0x03 }, /* go sleep */ - { 443250000, 36166667, 166666, 0xb4, 0x02 }, - { 542000000, 36166667, 166666, 0xb4, 0x08 }, - { 771000000, 36166667, 166666, 0xbc, 0x08 }, - { 999999999, 36166667, 166666, 0xf4, 0x08 }, + { 443250000, 166667, 0xb4, 0x02 }, + { 542000000, 166667, 0xb4, 0x08 }, + { 771000000, 166667, 0xbc, 0x08 }, + { 999999999, 166667, 0xf4, 0x08 }, }, }; EXPORT_SYMBOL(dvb_pll_thomson_dtt7579); @@ -46,11 +58,12 @@ struct dvb_pll_desc dvb_pll_thomson_dtt7610 = { .name = "Thomson dtt7610", .min = 44000000, .max = 958000000, + .iffreq= 44000000, .count = 3, .entries = { - { 157250000, 44000000, 62500, 0x8e, 0x39 }, - { 454000000, 44000000, 62500, 0x8e, 0x3a }, - { 999999999, 44000000, 62500, 0x8e, 0x3c }, + { 157250000, 62500, 0x8e, 0x39 }, + { 454000000, 62500, 0x8e, 0x3a }, + { 999999999, 62500, 0x8e, 0x3c }, }, }; EXPORT_SYMBOL(dvb_pll_thomson_dtt7610); @@ -66,14 +79,15 @@ struct dvb_pll_desc dvb_pll_thomson_dtt759x = { .min = 177000000, .max = 896000000, .setbw = thomson_dtt759x_bw, - .count = 6, + .iffreq= 36166667, + .sleepdata = (u8[]){ 2, 0x84, 0x03 }, + .count = 5, .entries = { - { 0, 36166667, 166666, 0x84, 0x03 }, - { 264000000, 36166667, 166666, 0xb4, 0x02 }, - { 470000000, 36166667, 166666, 0xbc, 0x02 }, - { 735000000, 36166667, 166666, 0xbc, 0x08 }, - { 835000000, 36166667, 166666, 0xf4, 0x08 }, - { 999999999, 36166667, 166666, 0xfc, 0x08 }, + { 264000000, 166667, 0xb4, 0x02 }, + { 470000000, 166667, 0xbc, 0x02 }, + { 735000000, 166667, 0xbc, 0x08 }, + { 835000000, 166667, 0xf4, 0x08 }, + { 999999999, 166667, 0xfc, 0x08 }, }, }; EXPORT_SYMBOL(dvb_pll_thomson_dtt759x); @@ -82,14 +96,15 @@ struct dvb_pll_desc dvb_pll_lg_z201 = { .name = "LG z201", .min = 174000000, .max = 862000000, - .count = 6, + .iffreq= 36166667, + .sleepdata = (u8[]){ 2, 0xbc, 0x03 }, + .count = 5, .entries = { - { 0, 36166667, 166666, 0xbc, 0x03 }, - { 157500000, 36166667, 166666, 0xbc, 0x01 }, - { 443250000, 36166667, 166666, 0xbc, 0x02 }, - { 542000000, 36166667, 166666, 0xbc, 0x04 }, - { 830000000, 36166667, 166666, 0xf4, 0x04 }, - { 999999999, 36166667, 166666, 0xfc, 0x04 }, + { 157500000, 166667, 0xbc, 0x01 }, + { 443250000, 166667, 0xbc, 0x02 }, + { 542000000, 166667, 0xbc, 0x04 }, + { 830000000, 166667, 0xf4, 0x04 }, + { 999999999, 166667, 0xfc, 0x04 }, }, }; EXPORT_SYMBOL(dvb_pll_lg_z201); @@ -98,11 +113,12 @@ struct dvb_pll_desc dvb_pll_microtune_4042 = { .name = "Microtune 4042 FI5", .min = 57000000, .max = 858000000, + .iffreq= 44000000, .count = 3, .entries = { - { 162000000, 44000000, 62500, 0x8e, 0xa1 }, - { 457000000, 44000000, 62500, 0x8e, 0x91 }, - { 999999999, 44000000, 62500, 0x8e, 0x31 }, + { 162000000, 62500, 0x8e, 0xa1 }, + { 457000000, 62500, 0x8e, 0x91 }, + { 999999999, 62500, 0x8e, 0x31 }, }, }; EXPORT_SYMBOL(dvb_pll_microtune_4042); @@ -112,11 +128,13 @@ struct dvb_pll_desc dvb_pll_thomson_dtt761x = { .name = "Thomson dtt761x", .min = 57000000, .max = 863000000, + .iffreq= 44000000, .count = 3, + .initdata = tua603x_agc103, .entries = { - { 147000000, 44000000, 62500, 0x8e, 0x39 }, - { 417000000, 44000000, 62500, 0x8e, 0x3a }, - { 999999999, 44000000, 62500, 0x8e, 0x3c }, + { 147000000, 62500, 0x8e, 0x39 }, + { 417000000, 62500, 0x8e, 0x3a }, + { 999999999, 62500, 0x8e, 0x3c }, }, }; EXPORT_SYMBOL(dvb_pll_thomson_dtt761x); @@ -125,17 +143,18 @@ struct dvb_pll_desc dvb_pll_unknown_1 = { .name = "unknown 1", /* used by dntv live dvb-t */ .min = 174000000, .max = 862000000, + .iffreq= 36166667, .count = 9, .entries = { - { 150000000, 36166667, 166666, 0xb4, 0x01 }, - { 173000000, 36166667, 166666, 0xbc, 0x01 }, - { 250000000, 36166667, 166666, 0xb4, 0x02 }, - { 400000000, 36166667, 166666, 0xbc, 0x02 }, - { 420000000, 36166667, 166666, 0xf4, 0x02 }, - { 470000000, 36166667, 166666, 0xfc, 0x02 }, - { 600000000, 36166667, 166666, 0xbc, 0x08 }, - { 730000000, 36166667, 166666, 0xf4, 0x08 }, - { 999999999, 36166667, 166666, 0xfc, 0x08 }, + { 150000000, 166667, 0xb4, 0x01 }, + { 173000000, 166667, 0xbc, 0x01 }, + { 250000000, 166667, 0xb4, 0x02 }, + { 400000000, 166667, 0xbc, 0x02 }, + { 420000000, 166667, 0xf4, 0x02 }, + { 470000000, 166667, 0xfc, 0x02 }, + { 600000000, 166667, 0xbc, 0x08 }, + { 730000000, 166667, 0xf4, 0x08 }, + { 999999999, 166667, 0xfc, 0x08 }, }, }; EXPORT_SYMBOL(dvb_pll_unknown_1); @@ -147,11 +166,12 @@ struct dvb_pll_desc dvb_pll_tua6010xs = { .name = "Infineon TUA6010XS", .min = 44250000, .max = 858000000, + .iffreq= 36125000, .count = 3, .entries = { - { 115750000, 36125000, 62500, 0x8e, 0x03 }, - { 403250000, 36125000, 62500, 0x8e, 0x06 }, - { 999999999, 36125000, 62500, 0x8e, 0x85 }, + { 115750000, 62500, 0x8e, 0x03 }, + { 403250000, 62500, 0x8e, 0x06 }, + { 999999999, 62500, 0x8e, 0x85 }, }, }; EXPORT_SYMBOL(dvb_pll_tua6010xs); @@ -161,12 +181,13 @@ struct dvb_pll_desc dvb_pll_env57h1xd5 = { .name = "Panasonic ENV57H1XD5", .min = 44250000, .max = 858000000, + .iffreq= 36125000, .count = 4, .entries = { - { 153000000, 36291666, 166666, 0xc2, 0x41 }, - { 470000000, 36291666, 166666, 0xc2, 0x42 }, - { 526000000, 36291666, 166666, 0xc2, 0x84 }, - { 999999999, 36291666, 166666, 0xc2, 0xa4 }, + { 153000000, 166667, 0xc2, 0x41 }, + { 470000000, 166667, 0xc2, 0x42 }, + { 526000000, 166667, 0xc2, 0x84 }, + { 999999999, 166667, 0xc2, 0xa4 }, }, }; EXPORT_SYMBOL(dvb_pll_env57h1xd5); @@ -185,20 +206,21 @@ struct dvb_pll_desc dvb_pll_tda665x = { .min = 44250000, .max = 858000000, .setbw = tda665x_bw, + .iffreq= 36166667, .count = 12, .entries = { - { 93834000, 36249333, 166667, 0xca, 0x61 /* 011 0 0 0 01 */ }, - { 123834000, 36249333, 166667, 0xca, 0xa1 /* 101 0 0 0 01 */ }, - { 161000000, 36249333, 166667, 0xca, 0xa1 /* 101 0 0 0 01 */ }, - { 163834000, 36249333, 166667, 0xca, 0xc2 /* 110 0 0 0 10 */ }, - { 253834000, 36249333, 166667, 0xca, 0x62 /* 011 0 0 0 10 */ }, - { 383834000, 36249333, 166667, 0xca, 0xa2 /* 101 0 0 0 10 */ }, - { 443834000, 36249333, 166667, 0xca, 0xc2 /* 110 0 0 0 10 */ }, - { 444000000, 36249333, 166667, 0xca, 0xc4 /* 110 0 0 1 00 */ }, - { 583834000, 36249333, 166667, 0xca, 0x64 /* 011 0 0 1 00 */ }, - { 793834000, 36249333, 166667, 0xca, 0xa4 /* 101 0 0 1 00 */ }, - { 444834000, 36249333, 166667, 0xca, 0xc4 /* 110 0 0 1 00 */ }, - { 861000000, 36249333, 166667, 0xca, 0xe4 /* 111 0 0 1 00 */ }, + { 93834000, 166667, 0xca, 0x61 /* 011 0 0 0 01 */ }, + { 123834000, 166667, 0xca, 0xa1 /* 101 0 0 0 01 */ }, + { 161000000, 166667, 0xca, 0xa1 /* 101 0 0 0 01 */ }, + { 163834000, 166667, 0xca, 0xc2 /* 110 0 0 0 10 */ }, + { 253834000, 166667, 0xca, 0x62 /* 011 0 0 0 10 */ }, + { 383834000, 166667, 0xca, 0xa2 /* 101 0 0 0 10 */ }, + { 443834000, 166667, 0xca, 0xc2 /* 110 0 0 0 10 */ }, + { 444000000, 166667, 0xca, 0xc4 /* 110 0 0 1 00 */ }, + { 583834000, 166667, 0xca, 0x64 /* 011 0 0 1 00 */ }, + { 793834000, 166667, 0xca, 0xa4 /* 101 0 0 1 00 */ }, + { 444834000, 166667, 0xca, 0xc4 /* 110 0 0 1 00 */ }, + { 861000000, 166667, 0xca, 0xe4 /* 111 0 0 1 00 */ }, } }; EXPORT_SYMBOL(dvb_pll_tda665x); @@ -216,12 +238,13 @@ struct dvb_pll_desc dvb_pll_tua6034 = { .name = "Infineon TUA6034", .min = 44250000, .max = 858000000, + .iffreq= 36166667, .count = 3, .setbw = tua6034_bw, .entries = { - { 174500000, 36166667, 62500, 0xce, 0x01 }, - { 230000000, 36166667, 62500, 0xce, 0x02 }, - { 999999999, 36166667, 62500, 0xce, 0x04 }, + { 174500000, 62500, 0xce, 0x01 }, + { 230000000, 62500, 0xce, 0x02 }, + { 999999999, 62500, 0xce, 0x04 }, }, }; EXPORT_SYMBOL(dvb_pll_tua6034); @@ -233,11 +256,13 @@ struct dvb_pll_desc dvb_pll_lg_tdvs_h06xf = { .name = "LG TDVS-H06xF", .min = 54000000, .max = 863000000, + .iffreq= 44000000, + .initdata = tua603x_agc103, .count = 3, .entries = { - { 165000000, 44000000, 62500, 0xce, 0x01 }, - { 450000000, 44000000, 62500, 0xce, 0x02 }, - { 999999999, 44000000, 62500, 0xce, 0x04 }, + { 165000000, 62500, 0xce, 0x01 }, + { 450000000, 62500, 0xce, 0x02 }, + { 999999999, 62500, 0xce, 0x04 }, }, }; EXPORT_SYMBOL(dvb_pll_lg_tdvs_h06xf); @@ -255,16 +280,17 @@ struct dvb_pll_desc dvb_pll_fmd1216me = { .name = "Philips FMD1216ME", .min = 50870000, .max = 858000000, + .iffreq= 36125000, .setbw = fmd1216me_bw, .count = 7, .entries = { - { 143870000, 36213333, 166667, 0xbc, 0x41 }, - { 158870000, 36213333, 166667, 0xf4, 0x41 }, - { 329870000, 36213333, 166667, 0xbc, 0x42 }, - { 441870000, 36213333, 166667, 0xf4, 0x42 }, - { 625870000, 36213333, 166667, 0xbc, 0x44 }, - { 803870000, 36213333, 166667, 0xf4, 0x44 }, - { 999999999, 36213333, 166667, 0xfc, 0x44 }, + { 143870000, 166667, 0xbc, 0x41 }, + { 158870000, 166667, 0xf4, 0x41 }, + { 329870000, 166667, 0xbc, 0x42 }, + { 441870000, 166667, 0xf4, 0x42 }, + { 625870000, 166667, 0xbc, 0x44 }, + { 803870000, 166667, 0xf4, 0x44 }, + { 999999999, 166667, 0xfc, 0x44 }, } }; EXPORT_SYMBOL(dvb_pll_fmd1216me); @@ -282,13 +308,14 @@ struct dvb_pll_desc dvb_pll_tded4 = { .name = "ALPS TDED4", .min = 47000000, .max = 863000000, + .iffreq= 36166667, .setbw = tded4_bw, .count = 4, .entries = { - { 153000000, 36166667, 166667, 0x85, 0x01 }, - { 470000000, 36166667, 166667, 0x85, 0x02 }, - { 823000000, 36166667, 166667, 0x85, 0x08 }, - { 999999999, 36166667, 166667, 0x85, 0x88 }, + { 153000000, 166667, 0x85, 0x01 }, + { 470000000, 166667, 0x85, 0x02 }, + { 823000000, 166667, 0x85, 0x08 }, + { 999999999, 166667, 0x85, 0x88 }, } }; EXPORT_SYMBOL(dvb_pll_tded4); @@ -300,12 +327,13 @@ struct dvb_pll_desc dvb_pll_tdhu2 = { .name = "ALPS TDHU2", .min = 54000000, .max = 864000000, + .iffreq= 44000000, .count = 4, .entries = { - { 162000000, 44000000, 62500, 0x85, 0x01 }, - { 426000000, 44000000, 62500, 0x85, 0x02 }, - { 782000000, 44000000, 62500, 0x85, 0x08 }, - { 999999999, 44000000, 62500, 0x85, 0x88 }, + { 162000000, 62500, 0x85, 0x01 }, + { 426000000, 62500, 0x85, 0x02 }, + { 782000000, 62500, 0x85, 0x08 }, + { 999999999, 62500, 0x85, 0x88 }, } }; EXPORT_SYMBOL(dvb_pll_tdhu2); @@ -317,11 +345,12 @@ struct dvb_pll_desc dvb_pll_tuv1236d = { .name = "Philips TUV1236D", .min = 54000000, .max = 864000000, + .iffreq= 44000000, .count = 3, .entries = { - { 157250000, 44000000, 62500, 0xc6, 0x41 }, - { 454000000, 44000000, 62500, 0xc6, 0x42 }, - { 999999999, 44000000, 62500, 0xc6, 0x44 }, + { 157250000, 62500, 0xc6, 0x41 }, + { 454000000, 62500, 0xc6, 0x42 }, + { 999999999, 62500, 0xc6, 0x44 }, }, }; EXPORT_SYMBOL(dvb_pll_tuv1236d); @@ -333,14 +362,15 @@ struct dvb_pll_desc dvb_pll_samsung_tbmv = { .name = "Samsung TBMV30111IN / TBMV30712IN1", .min = 54000000, .max = 860000000, + .iffreq= 44000000, .count = 6, .entries = { - { 172000000, 44000000, 166666, 0xb4, 0x01 }, - { 214000000, 44000000, 166666, 0xb4, 0x02 }, - { 467000000, 44000000, 166666, 0xbc, 0x02 }, - { 721000000, 44000000, 166666, 0xbc, 0x08 }, - { 841000000, 44000000, 166666, 0xf4, 0x08 }, - { 999999999, 44000000, 166666, 0xfc, 0x02 }, + { 172000000, 166667, 0xb4, 0x01 }, + { 214000000, 166667, 0xb4, 0x02 }, + { 467000000, 166667, 0xbc, 0x02 }, + { 721000000, 166667, 0xbc, 0x08 }, + { 841000000, 166667, 0xf4, 0x08 }, + { 999999999, 166667, 0xfc, 0x02 }, } }; EXPORT_SYMBOL(dvb_pll_samsung_tbmv); @@ -352,12 +382,13 @@ struct dvb_pll_desc dvb_pll_philips_sd1878_tda8261 = { .name = "Philips SD1878", .min = 950000, .max = 2150000, + .iffreq= 249, /* zero-IF, offset 249 is to round up */ .count = 4, .entries = { - { 1250000, 499, 500, 0xc4, 0x00}, - { 1550000, 499, 500, 0xc4, 0x40}, - { 2050000, 499, 500, 0xc4, 0x80}, - { 2150000, 499, 500, 0xc4, 0xc0}, + { 1250000, 500, 0xc4, 0x00}, + { 1550000, 500, 0xc4, 0x40}, + { 2050000, 500, 0xc4, 0x80}, + { 2150000, 500, 0xc4, 0xc0}, }, }; EXPORT_SYMBOL(dvb_pll_philips_sd1878_tda8261); @@ -388,18 +419,19 @@ struct dvb_pll_desc dvb_pll_philips_td1316 = { .name = "Philips TD1316", .min = 87000000, .max = 895000000, + .iffreq= 36166667, .setbw = td1316_bw, .count = 9, .entries = { - { 93834000, 36166000, 166666, 0xca, 0x60}, - { 123834000, 36166000, 166666, 0xca, 0xa0}, - { 163834000, 36166000, 166666, 0xca, 0xc0}, - { 253834000, 36166000, 166666, 0xca, 0x60}, - { 383834000, 36166000, 166666, 0xca, 0xa0}, - { 443834000, 36166000, 166666, 0xca, 0xc0}, - { 583834000, 36166000, 166666, 0xca, 0x60}, - { 793834000, 36166000, 166666, 0xca, 0xa0}, - { 858834000, 36166000, 166666, 0xca, 0xe0}, + { 93834000, 166667, 0xca, 0x60}, + { 123834000, 166667, 0xca, 0xa0}, + { 163834000, 166667, 0xca, 0xc0}, + { 253834000, 166667, 0xca, 0x60}, + { 383834000, 166667, 0xca, 0xa0}, + { 443834000, 166667, 0xca, 0xc0}, + { 583834000, 166667, 0xca, 0x60}, + { 793834000, 166667, 0xca, 0xa0}, + { 858834000, 166667, 0xca, 0xe0}, }, }; EXPORT_SYMBOL(dvb_pll_philips_td1316); @@ -409,15 +441,41 @@ struct dvb_pll_desc dvb_pll_thomson_fe6600 = { .name = "Thomson FE6600", .min = 44250000, .max = 858000000, + .iffreq= 36125000, .count = 4, .entries = { - { 250000000, 36213333, 166667, 0xb4, 0x12 }, - { 455000000, 36213333, 166667, 0xfe, 0x11 }, - { 775500000, 36213333, 166667, 0xbc, 0x18 }, - { 999999999, 36213333, 166667, 0xf4, 0x18 }, + { 250000000, 166667, 0xb4, 0x12 }, + { 455000000, 166667, 0xfe, 0x11 }, + { 775500000, 166667, 0xbc, 0x18 }, + { 999999999, 166667, 0xf4, 0x18 }, } }; EXPORT_SYMBOL(dvb_pll_thomson_fe6600); +static void opera1_bw(u8 *buf, u32 freq, int bandwidth) +{ + if (bandwidth == BANDWIDTH_8_MHZ) + buf[2] |= 0x08; +} + +struct dvb_pll_desc dvb_pll_opera1 = { + .name = "Opera Tuner", + .min = 900000, + .max = 2250000, + .iffreq= 0, + .setbw = opera1_bw, + .count = 8, + .entries = { + { 1064000, 500, 0xe5, 0xc6 }, + { 1169000, 500, 0xe5, 0xe6 }, + { 1299000, 500, 0xe5, 0x24 }, + { 1444000, 500, 0xe5, 0x44 }, + { 1606000, 500, 0xe5, 0x64 }, + { 1777000, 500, 0xe5, 0x84 }, + { 1941000, 500, 0xe5, 0xa4 }, + { 2250000, 500, 0xe5, 0xc4 }, + } +}; +EXPORT_SYMBOL(dvb_pll_opera1); struct dvb_pll_priv { /* i2c details */ @@ -459,7 +517,8 @@ int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf, if (i == desc->count) return -EINVAL; - div = (freq + desc->entries[i].offset) / desc->entries[i].stepsize; + div = (freq + desc->iffreq + desc->entries[i].stepsize/2) / + desc->entries[i].stepsize; buf[0] = div >> 8; buf[1] = div & 0xff; buf[2] = desc->entries[i].config; @@ -473,7 +532,7 @@ int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf, desc->name, div, buf[0], buf[1], buf[2], buf[3]); // calculate the frequency we set it to - return (div * desc->entries[i].stepsize) - desc->entries[i].offset; + return (div * desc->entries[i].stepsize) - desc->iffreq; } EXPORT_SYMBOL(dvb_pll_configure); @@ -487,35 +546,27 @@ static int dvb_pll_release(struct dvb_frontend *fe) static int dvb_pll_sleep(struct dvb_frontend *fe) { struct dvb_pll_priv *priv = fe->tuner_priv; - u8 buf[4]; - struct i2c_msg msg = - { .addr = priv->pll_i2c_address, .flags = 0, - .buf = buf, .len = sizeof(buf) }; - int i; - int result; if (priv->i2c == NULL) return -EINVAL; - for (i = 0; i < priv->pll_desc->count; i++) { - if (priv->pll_desc->entries[i].limit == 0) - break; - } - if (i == priv->pll_desc->count) - return 0; + if (priv->pll_desc->sleepdata) { + struct i2c_msg msg = { .flags = 0, + .addr = priv->pll_i2c_address, + .buf = priv->pll_desc->sleepdata + 1, + .len = priv->pll_desc->sleepdata[0] }; - buf[0] = 0; - buf[1] = 0; - buf[2] = priv->pll_desc->entries[i].config; - buf[3] = priv->pll_desc->entries[i].cb; + 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; + 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; } - - return 0; + /* Shouldn't be called when initdata is NULL, maybe BUG()? */ + return -EINVAL; } static int dvb_pll_set_params(struct dvb_frontend *fe, @@ -599,9 +650,35 @@ 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, + .init = dvb_pll_init, .set_params = dvb_pll_set_params, .calc_regs = dvb_pll_calc_regs, .get_frequency = dvb_pll_get_frequency, @@ -640,9 +717,14 @@ 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 = NULL; + if (!desc->sleepdata) + fe->ops.tuner_ops.sleep = NULL; fe->tuner_priv = priv; return fe; diff --git a/drivers/media/dvb/frontends/dvb-pll.h b/drivers/media/dvb/frontends/dvb-pll.h index 681186a5e5eb..5209f46f0893 100644 --- a/drivers/media/dvb/frontends/dvb-pll.h +++ b/drivers/media/dvb/frontends/dvb-pll.h @@ -12,11 +12,13 @@ struct dvb_pll_desc { char *name; u32 min; u32 max; + u32 iffreq; void (*setbw)(u8 *buf, u32 freq, int bandwidth); + u8 *initdata; + u8 *sleepdata; int count; struct { u32 limit; - u32 offset; u32 stepsize; u8 config; u8 cb; @@ -46,6 +48,7 @@ extern struct dvb_pll_desc dvb_pll_philips_sd1878_tda8261; extern struct dvb_pll_desc dvb_pll_philips_td1316; extern struct dvb_pll_desc dvb_pll_thomson_fe6600; +extern struct dvb_pll_desc dvb_pll_opera1; extern int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf, u32 freq, int bandwidth); @@ -59,9 +62,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/drivers/media/dvb/frontends/lgdt330x.c b/drivers/media/dvb/frontends/lgdt330x.c index 68aad0f6519f..e25286e2d431 100644 --- a/drivers/media/dvb/frontends/lgdt330x.c +++ b/drivers/media/dvb/frontends/lgdt330x.c @@ -475,7 +475,7 @@ static int lgdt3302_read_status(struct dvb_frontend* fe, fe_status_t* status) *status |= FE_HAS_CARRIER; break; default: - printk("KERN_WARNING lgdt330x: %s: Modulation set to unsupported value\n", __FUNCTION__); + printk(KERN_WARNING "lgdt330x: %s: Modulation set to unsupported value\n", __FUNCTION__); } return 0; @@ -534,7 +534,7 @@ static int lgdt3303_read_status(struct dvb_frontend* fe, fe_status_t* status) } break; default: - printk("KERN_WARNING lgdt330x: %s: Modulation set to unsupported value\n", __FUNCTION__); + printk(KERN_WARNING "lgdt330x: %s: Modulation set to unsupported value\n", __FUNCTION__); } return 0; } diff --git a/drivers/media/dvb/frontends/lgh06xf.c b/drivers/media/dvb/frontends/lgh06xf.c deleted file mode 100644 index 2202d0cc878b..000000000000 --- a/drivers/media/dvb/frontends/lgh06xf.c +++ /dev/null @@ -1,134 +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. */ - buf[0] = buf[2]; - buf[0] &= ~0x20; - buf[0] |= 0x18; - buf[1] = 0x50; - msg.len = 2; - 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/drivers/media/dvb/frontends/lgh06xf.h b/drivers/media/dvb/frontends/lgh06xf.h deleted file mode 100644 index 510b4bedfb24..000000000000 --- a/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/drivers/media/dvb/frontends/or51132.c b/drivers/media/dvb/frontends/or51132.c index 5a3a6e53cda2..4e0aca7c67aa 100644 --- a/drivers/media/dvb/frontends/or51132.c +++ b/drivers/media/dvb/frontends/or51132.c @@ -1,6 +1,9 @@ /* * Support for OR51132 (pcHDTV HD-3000) - VSB/QAM * + * + * Copyright (C) 2007 Trent Piepho <xyzzy@speakeasy.org> + * * Copyright (C) 2005 Kirk Lapray <kirk_lapray@bigfoot.com> * * Based on code from Jack Kelliher (kelliher@xmission.com) @@ -69,46 +72,70 @@ struct or51132_state u32 current_frequency; }; -static int i2c_writebytes (struct or51132_state* state, u8 reg, u8 *buf, int len) + +/* Write buffer to demod */ +static int or51132_writebuf(struct or51132_state *state, const u8 *buf, int len) { int err; - struct i2c_msg msg; - msg.addr = reg; - msg.flags = 0; - msg.len = len; - msg.buf = buf; + struct i2c_msg msg = { .addr = state->config->demod_address, + .flags = 0, .buf = (u8*)buf, .len = len }; + /* msleep(20); */ /* doesn't appear to be necessary */ if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) { - printk(KERN_WARNING "or51132: i2c_writebytes error (addr %02x, err == %i)\n", reg, err); + printk(KERN_WARNING "or51132: I2C write (addr 0x%02x len %d) error: %d\n", + msg.addr, msg.len, err); return -EREMOTEIO; } - return 0; } -static u8 i2c_readbytes (struct or51132_state* state, u8 reg, u8* buf, int len) +/* Write constant bytes, e.g. or51132_writebytes(state, 0x04, 0x42, 0x00); + Less code and more efficient that loading a buffer on the stack with + the bytes to send and then calling or51132_writebuf() on that. */ +#define or51132_writebytes(state, data...) \ + ({ const static u8 _data[] = {data}; \ + or51132_writebuf(state, _data, sizeof(_data)); }) + +/* Read data from demod into buffer. Returns 0 on success. */ +static int or51132_readbuf(struct or51132_state *state, u8 *buf, int len) { int err; - struct i2c_msg msg; - msg.addr = reg; - msg.flags = I2C_M_RD; - msg.len = len; - msg.buf = buf; + struct i2c_msg msg = { .addr = state->config->demod_address, + .flags = I2C_M_RD, .buf = buf, .len = len }; + /* msleep(20); */ /* doesn't appear to be necessary */ if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) { - printk(KERN_WARNING "or51132: i2c_readbytes error (addr %02x, err == %i)\n", reg, err); + printk(KERN_WARNING "or51132: I2C read (addr 0x%02x len %d) error: %d\n", + msg.addr, msg.len, err); return -EREMOTEIO; } - return 0; } +/* Reads a 16-bit demod register. Returns <0 on error. */ +static int or51132_readreg(struct or51132_state *state, u8 reg) +{ + u8 buf[2] = { 0x04, reg }; + struct i2c_msg msg[2] = { + {.addr = state->config->demod_address, .flags = 0, + .buf = buf, .len = 2 }, + {.addr = state->config->demod_address, .flags = I2C_M_RD, + .buf = buf, .len = 2 }}; + int err; + + if ((err = i2c_transfer(state->i2c, msg, 2)) != 2) { + printk(KERN_WARNING "or51132: I2C error reading register %d: %d\n", + reg, err); + return -EREMOTEIO; + } + return le16_to_cpup((u16*)buf); +} + static int or51132_load_firmware (struct dvb_frontend* fe, const struct firmware *fw) { struct or51132_state* state = fe->demodulator_priv; - static u8 run_buf[] = {0x7F,0x01}; + const static u8 run_buf[] = {0x7F,0x01}; u8 rec_buf[8]; - u8 cmd_buf[3]; u32 firmwareAsize, firmwareBsize; int i,ret; @@ -121,30 +148,21 @@ static int or51132_load_firmware (struct dvb_frontend* fe, const struct firmware dprintk("FirmwareB is %i bytes\n",firmwareBsize); /* Upload firmware */ - if ((ret = i2c_writebytes(state,state->config->demod_address, - &fw->data[8],firmwareAsize))) { + if ((ret = or51132_writebuf(state, &fw->data[8], firmwareAsize))) { printk(KERN_WARNING "or51132: load_firmware error 1\n"); return ret; } - msleep(1); /* 1ms */ - if ((ret = i2c_writebytes(state,state->config->demod_address, - &fw->data[8+firmwareAsize],firmwareBsize))) { + if ((ret = or51132_writebuf(state, &fw->data[8+firmwareAsize], + firmwareBsize))) { printk(KERN_WARNING "or51132: load_firmware error 2\n"); return ret; } - msleep(1); /* 1ms */ - if ((ret = i2c_writebytes(state,state->config->demod_address, - run_buf,2))) { + if ((ret = or51132_writebuf(state, run_buf, 2))) { printk(KERN_WARNING "or51132: load_firmware error 3\n"); return ret; } - - /* Wait at least 5 msec */ - msleep(20); /* 10ms */ - - if ((ret = i2c_writebytes(state,state->config->demod_address, - run_buf,2))) { + if ((ret = or51132_writebuf(state, run_buf, 2))) { printk(KERN_WARNING "or51132: load_firmware error 4\n"); return ret; } @@ -154,43 +172,25 @@ static int or51132_load_firmware (struct dvb_frontend* fe, const struct firmware /* Read back ucode version to besure we loaded correctly and are really up and running */ /* Get uCode version */ - cmd_buf[0] = 0x10; - cmd_buf[1] = 0x10; - cmd_buf[2] = 0x00; - msleep(20); /* 20ms */ - if ((ret = i2c_writebytes(state,state->config->demod_address, - cmd_buf,3))) { + if ((ret = or51132_writebytes(state, 0x10, 0x10, 0x00))) { printk(KERN_WARNING "or51132: load_firmware error a\n"); return ret; } - - cmd_buf[0] = 0x04; - cmd_buf[1] = 0x17; - msleep(20); /* 20ms */ - if ((ret = i2c_writebytes(state,state->config->demod_address, - cmd_buf,2))) { + if ((ret = or51132_writebytes(state, 0x04, 0x17))) { printk(KERN_WARNING "or51132: load_firmware error b\n"); return ret; } - - cmd_buf[0] = 0x00; - cmd_buf[1] = 0x00; - msleep(20); /* 20ms */ - if ((ret = i2c_writebytes(state,state->config->demod_address, - cmd_buf,2))) { + if ((ret = or51132_writebytes(state, 0x00, 0x00))) { printk(KERN_WARNING "or51132: load_firmware error c\n"); return ret; } - - for(i=0;i<4;i++) { - msleep(20); /* 20ms */ + for (i=0;i<4;i++) { /* Once upon a time, this command might have had something to do with getting the firmware version, but it's not used anymore: {0x04,0x00,0x30,0x00,i+1} */ /* Read 8 bytes, two bytes at a time */ - if ((ret = i2c_readbytes(state,state->config->demod_address, - &rec_buf[i*2],2))) { + if ((ret = or51132_readbuf(state, &rec_buf[i*2], 2))) { printk(KERN_WARNING "or51132: load_firmware error d - %d\n",i); return ret; @@ -204,12 +204,7 @@ static int or51132_load_firmware (struct dvb_frontend* fe, const struct firmware rec_buf[3],rec_buf[2]>>4,rec_buf[2]&0x0f, rec_buf[5],rec_buf[4]>>4,rec_buf[4]&0x0f); - cmd_buf[0] = 0x10; - cmd_buf[1] = 0x00; - cmd_buf[2] = 0x00; - msleep(20); /* 20ms */ - if ((ret = i2c_writebytes(state,state->config->demod_address, - cmd_buf,3))) { + if ((ret = or51132_writebytes(state, 0x10, 0x00, 0x00))) { printk(KERN_WARNING "or51132: load_firmware error e\n"); return ret; } @@ -241,70 +236,55 @@ static int or51132_sleep(struct dvb_frontend* fe) static int or51132_setmode(struct dvb_frontend* fe) { struct or51132_state* state = fe->demodulator_priv; - unsigned char cmd_buf[3]; + u8 cmd_buf1[3] = {0x04, 0x01, 0x5f}; + u8 cmd_buf2[3] = {0x1c, 0x00, 0 }; dprintk("setmode %d\n",(int)state->current_modulation); - /* set operation mode in Receiver 1 register; */ - cmd_buf[0] = 0x04; - cmd_buf[1] = 0x01; + switch (state->current_modulation) { - case QAM_256: - case QAM_64: - case QAM_AUTO: - /* Auto-deinterleave; MPEG ser, MPEG2tr, phase noise-high*/ - cmd_buf[2] = 0x5F; - break; case VSB_8: - /* Auto CH, Auto NTSC rej, MPEGser, MPEG2tr, phase noise-high*/ - cmd_buf[2] = 0x50; + /* Auto CH, Auto NTSC rej, MPEGser, MPEG2tr, phase noise-high */ + cmd_buf1[2] = 0x50; + /* REC MODE inv IF spectrum, Normal */ + cmd_buf2[1] = 0x03; + /* Channel MODE ATSC/VSB8 */ + cmd_buf2[2] = 0x06; break; - default: - printk("setmode:Modulation set to unsupported value\n"); - }; - if (i2c_writebytes(state,state->config->demod_address, - cmd_buf,3)) { - printk(KERN_WARNING "or51132: set_mode error 1\n"); - return -1; - } - dprintk("or51132: set #1 to %02x\n", cmd_buf[2]); - - /* Set operation mode in Receiver 6 register */ - cmd_buf[0] = 0x1C; - switch (state->current_modulation) { + /* All QAM modes are: + Auto-deinterleave; MPEGser, MPEG2tr, phase noise-high + REC MODE Normal Carrier Lock */ case QAM_AUTO: - /* REC MODE Normal Carrier Lock */ - cmd_buf[1] = 0x00; /* Channel MODE Auto QAM64/256 */ - cmd_buf[2] = 0x4f; + cmd_buf2[2] = 0x4f; break; case QAM_256: - /* REC MODE Normal Carrier Lock */ - cmd_buf[1] = 0x00; /* Channel MODE QAM256 */ - cmd_buf[2] = 0x45; + cmd_buf2[2] = 0x45; break; case QAM_64: - /* REC MODE Normal Carrier Lock */ - cmd_buf[1] = 0x00; /* Channel MODE QAM64 */ - cmd_buf[2] = 0x43; - break; - case VSB_8: - /* REC MODE inv IF spectrum, Normal */ - cmd_buf[1] = 0x03; - /* Channel MODE ATSC/VSB8 */ - cmd_buf[2] = 0x06; + cmd_buf2[2] = 0x43; break; default: - printk("setmode: Modulation set to unsupported value\n"); - }; - msleep(20); /* 20ms */ - if (i2c_writebytes(state,state->config->demod_address, - cmd_buf,3)) { + printk(KERN_WARNING + "or51132: setmode: Modulation set to unsupported value (%d)\n", + state->current_modulation); + return -EINVAL; + } + + /* Set Receiver 1 register */ + if (or51132_writebuf(state, cmd_buf1, 3)) { + printk(KERN_WARNING "or51132: set_mode error 1\n"); + return -EREMOTEIO; + } + dprintk("set #1 to %02x\n", cmd_buf1[2]); + + /* Set operation mode in Receiver 6 register */ + if (or51132_writebuf(state, cmd_buf2, 3)) { printk(KERN_WARNING "or51132: set_mode error 2\n"); - return -1; + return -EREMOTEIO; } - dprintk("or51132: set #6 to 0x%02x%02x\n", cmd_buf[1], cmd_buf[2]); + dprintk("set #6 to 0x%02x%02x\n", cmd_buf2[1], cmd_buf2[2]); return 0; } @@ -401,28 +381,23 @@ static int or51132_get_parameters(struct dvb_frontend* fe, struct dvb_frontend_parameters *param) { struct or51132_state* state = fe->demodulator_priv; - u8 buf[2]; + int status; + int retry = 1; +start: /* Receiver Status */ - buf[0]=0x04; - buf[1]=0x00; - msleep(30); /* 30ms */ - if (i2c_writebytes(state,state->config->demod_address,buf,2)) { - printk(KERN_WARNING "or51132: get_parameters write error\n"); - return -EREMOTEIO; - } - msleep(30); /* 30ms */ - if (i2c_readbytes(state,state->config->demod_address,buf,2)) { - printk(KERN_WARNING "or51132: get_parameters read error\n"); + if ((status = or51132_readreg(state, 0x00)) < 0) { + printk(KERN_WARNING "or51132: get_parameters: error reading receiver status\n"); return -EREMOTEIO; } - switch(buf[0]) { + switch(status&0xff) { case 0x06: param->u.vsb.modulation = VSB_8; break; case 0x43: param->u.vsb.modulation = QAM_64; break; case 0x45: param->u.vsb.modulation = QAM_256; break; default: + if (retry--) goto start; printk(KERN_WARNING "or51132: unknown status 0x%02x\n", - buf[0]); + status&0xff); return -EREMOTEIO; } @@ -438,32 +413,21 @@ static int or51132_get_parameters(struct dvb_frontend* fe, static int or51132_read_status(struct dvb_frontend* fe, fe_status_t* status) { struct or51132_state* state = fe->demodulator_priv; - unsigned char rec_buf[2]; - unsigned char snd_buf[2]; - *status = 0; + int reg; /* Receiver Status */ - snd_buf[0]=0x04; - snd_buf[1]=0x00; - msleep(30); /* 30ms */ - if (i2c_writebytes(state,state->config->demod_address,snd_buf,2)) { - printk(KERN_WARNING "or51132: read_status write error\n"); - return -1; - } - msleep(30); /* 30ms */ - if (i2c_readbytes(state,state->config->demod_address,rec_buf,2)) { - printk(KERN_WARNING "or51132: read_status read error\n"); - return -1; - } - dprintk("read_status %x %x\n",rec_buf[0],rec_buf[1]); - - if (rec_buf[1] & 0x01) { /* Receiver Lock */ - *status |= FE_HAS_SIGNAL; - *status |= FE_HAS_CARRIER; - *status |= FE_HAS_VITERBI; - *status |= FE_HAS_SYNC; - *status |= FE_HAS_LOCK; + if ((reg = or51132_readreg(state, 0x00)) < 0) { + printk(KERN_WARNING "or51132: read_status: error reading receiver status: %d\n", reg); + *status = 0; + return -EREMOTEIO; } + dprintk("%s: read_status %04x\n", __FUNCTION__, reg); + + if (reg & 0x0100) /* Receiver Lock */ + *status = FE_HAS_SIGNAL|FE_HAS_CARRIER|FE_HAS_VITERBI| + FE_HAS_SYNC|FE_HAS_LOCK; + else + *status = 0; return 0; } @@ -506,47 +470,30 @@ static u32 calculate_snr(u32 mse, u32 c) static int or51132_read_snr(struct dvb_frontend* fe, u16* snr) { struct or51132_state* state = fe->demodulator_priv; - u8 rec_buf[2]; - u8 snd_buf[2]; - u32 noise; - u32 c; - u32 usK; - - /* Register is same for VSB or QAM firmware */ - snd_buf[0]=0x04; - snd_buf[1]=0x02; /* SNR after Equalizer */ - msleep(30); /* 30ms */ - if (i2c_writebytes(state,state->config->demod_address,snd_buf,2)) { - printk(KERN_WARNING "or51132: snr write error\n"); - return -EREMOTEIO; - } - msleep(30); /* 30ms */ - if (i2c_readbytes(state,state->config->demod_address,rec_buf,2)) { - printk(KERN_WARNING "or51132: snr read error\n"); + int noise, reg; + u32 c, usK = 0; + int retry = 1; + +start: + /* SNR after Equalizer */ + noise = or51132_readreg(state, 0x02); + if (noise < 0) { + printk(KERN_WARNING "or51132: read_snr: error reading equalizer\n"); return -EREMOTEIO; } - noise = rec_buf[0] | (rec_buf[1] << 8); - dprintk("read_snr noise %x %x (%i)\n",rec_buf[0],rec_buf[1],noise); + dprintk("read_snr noise (%d)\n", noise); /* Read status, contains modulation type for QAM_AUTO and NTSC filter for VSB */ - snd_buf[0]=0x04; - snd_buf[1]=0x00; /* Status register */ - msleep(30); /* 30ms */ - if (i2c_writebytes(state,state->config->demod_address,snd_buf,2)) { - printk(KERN_WARNING "or51132: status write error\n"); - return -EREMOTEIO; - } - msleep(30); /* 30ms */ - if (i2c_readbytes(state,state->config->demod_address,rec_buf,2)) { - printk(KERN_WARNING "or51132: status read error\n"); + reg = or51132_readreg(state, 0x00); + if (reg < 0) { + printk(KERN_WARNING "or51132: read_snr: error reading receiver status\n"); return -EREMOTEIO; } - usK = 0; - switch (rec_buf[0]) { + switch (reg&0xff) { case 0x06: - usK = (rec_buf[1] & 0x10) ? 0x03000000 : 0; + if (reg & 0x1000) usK = 3 << 24; /* Fall through to QAM64 case */ case 0x43: c = 150204167; @@ -555,11 +502,12 @@ static int or51132_read_snr(struct dvb_frontend* fe, u16* snr) c = 150290396; break; default: - printk(KERN_ERR "or51132: unknown status 0x%02x\n", rec_buf[0]); + printk(KERN_WARNING "or51132: unknown status 0x%02x\n", reg&0xff); + if (retry--) goto start; return -EREMOTEIO; } dprintk("%s: modulation %02x, NTSC rej O%s\n", __FUNCTION__, - rec_buf[0], rec_buf[1]&0x10?"n":"ff"); + reg&0xff, reg&0x1000?"n":"ff"); /* Calculate SNR using noise, c, and NTSC rejection correction */ state->snr = calculate_snr(noise, c) - usK; @@ -671,6 +619,7 @@ MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); MODULE_DESCRIPTION("OR51132 ATSC [pcHDTV HD-3000] (8VSB & ITU J83 AnnexB FEC QAM64/256) Demodulator Driver"); MODULE_AUTHOR("Kirk Lapray"); +MODULE_AUTHOR("Trent Piepho"); MODULE_LICENSE("GPL"); EXPORT_SYMBOL(or51132_attach); diff --git a/drivers/media/dvb/frontends/tda10021.c b/drivers/media/dvb/frontends/tda10021.c index 5b9c5bb29b23..110536843e8e 100644 --- a/drivers/media/dvb/frontends/tda10021.c +++ b/drivers/media/dvb/frontends/tda10021.c @@ -30,13 +30,13 @@ #include <linux/slab.h> #include "dvb_frontend.h" -#include "tda10021.h" +#include "tda1002x.h" struct tda10021_state { struct i2c_adapter* i2c; /* configuration settings */ - const struct tda10021_config* config; + const struct tda1002x_config* config; struct dvb_frontend frontend; u8 pwm; @@ -53,9 +53,6 @@ struct tda10021_state { static int verbose; #define XIN 57840000UL -#define DISABLE_INVERSION(reg0) do { reg0 |= 0x20; } while (0) -#define ENABLE_INVERSION(reg0) do { reg0 &= ~0x20; } while (0) -#define HAS_INVERSION(reg0) (!(reg0 & 0x20)) #define FIN (XIN >> 4) @@ -64,7 +61,7 @@ static u8 tda10021_inittab[0x40]= { 0x73, 0x6a, 0x23, 0x0a, 0x02, 0x37, 0x77, 0x1a, 0x37, 0x6a, 0x17, 0x8a, 0x1e, 0x86, 0x43, 0x40, - 0xb8, 0x3f, 0xa0, 0x00, 0xcd, 0x01, 0x00, 0xff, + 0xb8, 0x3f, 0xa1, 0x00, 0xcd, 0x01, 0x00, 0xff, 0x11, 0x00, 0x7c, 0x31, 0x30, 0x20, 0x00, 0x00, 0x02, 0x00, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x33, 0x11, 0x0d, 0x95, 0x08, 0x58, @@ -97,7 +94,8 @@ static u8 tda10021_readreg (struct tda10021_state* state, u8 reg) int ret; ret = i2c_transfer (state->i2c, msg, 2); - if (ret != 2) + // Don't print an error message if the id is read. + if (ret != 2 && reg != 0x1a) printk("DVB: TDA10021: %s: readreg error (ret == %i)\n", __FUNCTION__, ret); return b1[0]; @@ -136,10 +134,10 @@ static int tda10021_setup_reg0 (struct tda10021_state* state, u8 reg0, { reg0 |= state->reg0 & 0x63; - if (INVERSION_ON == inversion) - ENABLE_INVERSION(reg0); - else if (INVERSION_OFF == inversion) - DISABLE_INVERSION(reg0); + if ((INVERSION_ON == inversion) ^ (state->config->invert == 0)) + reg0 &= ~0x20; + else + reg0 |= 0x20; _tda10021_writereg (state, 0x00, reg0 & 0xfe); _tda10021_writereg (state, 0x00, reg0 | 0x01); @@ -201,16 +199,6 @@ static int tda10021_set_symbolrate (struct tda10021_state* state, u32 symbolrate return 0; } -static int tda10021_write(struct dvb_frontend* fe, u8 *buf, int len) -{ - struct tda10021_state* state = fe->demodulator_priv; - - if (len != 2) - return -EINVAL; - - return _tda10021_writereg(state, buf[0], buf[1]); -} - static int tda10021_init (struct dvb_frontend *fe) { struct tda10021_state* state = fe->demodulator_priv; @@ -258,6 +246,9 @@ static int tda10021_set_parameters (struct dvb_frontend *fe, if (qam < 0 || qam > 5) return -EINVAL; + if (p->inversion != INVERSION_ON && p->inversion != INVERSION_OFF) + return -EINVAL; + //printk("tda10021: set frequency to %d qam=%d symrate=%d\n", p->frequency,qam,p->u.qam.symbol_rate); if (fe->ops.tuner_ops.set_params) { @@ -366,7 +357,7 @@ static int tda10021_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_pa -((s32)p->u.qam.symbol_rate * afc) >> 10); } - p->inversion = HAS_INVERSION(state->reg0) ? INVERSION_ON : INVERSION_OFF; + p->inversion = ((state->reg0 & 0x20) == 0x20) ^ (state->config->invert != 0) ? INVERSION_ON : INVERSION_OFF; p->u.qam.modulation = ((state->reg0 >> 2) & 7) + QAM_16; p->u.qam.fec_inner = FEC_NONE; @@ -408,11 +399,12 @@ static void tda10021_release(struct dvb_frontend* fe) static struct dvb_frontend_ops tda10021_ops; -struct dvb_frontend* tda10021_attach(const struct tda10021_config* config, +struct dvb_frontend* tda10021_attach(const struct tda1002x_config* config, struct i2c_adapter* i2c, u8 pwm) { struct tda10021_state* state = NULL; + u8 id; /* allocate memory for the internal state */ state = kmalloc(sizeof(struct tda10021_state), GFP_KERNEL); @@ -425,7 +417,11 @@ struct dvb_frontend* tda10021_attach(const struct tda10021_config* config, state->reg0 = tda10021_inittab[0]; /* check if the demod is there */ - if ((tda10021_readreg(state, 0x1a) & 0xf0) != 0x70) goto error; + id = tda10021_readreg(state, 0x1a); + if ((id & 0xf0) != 0x70) goto error; + + printk("TDA10021: i2c-addr = 0x%02x, id = 0x%02x\n", + state->config->demod_address, id); /* create dvb_frontend */ memcpy(&state->frontend.ops, &tda10021_ops, sizeof(struct dvb_frontend_ops)); @@ -447,7 +443,7 @@ static struct dvb_frontend_ops tda10021_ops = { .frequency_max = 858000000, .symbol_rate_min = (XIN/2)/64, /* SACLK/64 == (XIN/2)/64 */ .symbol_rate_max = (XIN/2)/4, /* SACLK/4 */ -#if 0 + #if 0 .frequency_tolerance = ???, .symbol_rate_tolerance = ???, /* ppm */ /* == 8% (spec p. 5) */ #endif @@ -461,7 +457,6 @@ static struct dvb_frontend_ops tda10021_ops = { .init = tda10021_init, .sleep = tda10021_sleep, - .write = tda10021_write, .i2c_gate_ctrl = tda10021_i2c_gate_ctrl, .set_frontend = tda10021_set_parameters, diff --git a/drivers/media/dvb/frontends/tda10023.c b/drivers/media/dvb/frontends/tda10023.c new file mode 100644 index 000000000000..da796e784be3 --- /dev/null +++ b/drivers/media/dvb/frontends/tda10023.c @@ -0,0 +1,540 @@ +/* + TDA10023 - DVB-C decoder + (as used in Philips CU1216-3 NIM and the Reelbox DVB-C tuner card) + + Copyright (C) 2005 Georg Acher, BayCom GmbH (acher at baycom dot de) + Copyright (c) 2006 Hartmut Birr (e9hack at gmail dot com) + + Remotely based on tda10021.c + Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.de> + Copyright (C) 2004 Markus Schulz <msc@antzsystem.de> + Support for TDA10021 + + 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/delay.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/string.h> +#include <linux/slab.h> + +#include <asm/div64.h> + +#include "dvb_frontend.h" +#include "tda1002x.h" + + +struct tda10023_state { + struct i2c_adapter* i2c; + /* configuration settings */ + const struct tda1002x_config* config; + struct dvb_frontend frontend; + + u8 pwm; + u8 reg0; +}; + + +#define dprintk(x...) + +static int verbose; + +#define XTAL 28920000UL +#define PLL_M 8UL +#define PLL_P 4UL +#define PLL_N 1UL +#define SYSCLK (XTAL*PLL_M/(PLL_N*PLL_P)) // -> 57840000 + +static u8 tda10023_inittab[]={ + // reg mask val + 0x2a,0xff,0x02, // PLL3, Bypass, Power Down + 0xff,0x64,0x00, // Sleep 100ms + 0x2a,0xff,0x03, // PLL3, Bypass, Power Down + 0xff,0x64,0x00, // Sleep 100ms + 0x28,0xff,PLL_M-1, // PLL1 M=8 + 0x29,0xff,((PLL_P-1)<<6)|(PLL_N-1), // PLL2 + 0x00,0xff,0x23, // GPR FSAMPLING=1 + 0x2a,0xff,0x08, // PLL3 PSACLK=1 + 0xff,0x64,0x00, // Sleep 100ms + 0x1f,0xff,0x00, // RESET + 0xff,0x64,0x00, // Sleep 100ms + 0xe6,0x0c,0x04, // RSCFG_IND + 0x10,0xc0,0x80, // DECDVBCFG1 PBER=1 + + 0x0e,0xff,0x82, // GAIN1 + 0x03,0x08,0x08, // CLKCONF DYN=1 + 0x2e,0xbf,0x30, // AGCCONF2 TRIAGC=0,POSAGC=ENAGCIF=1 PPWMTUN=0 PPWMIF=0 + 0x01,0xff,0x30, // AGCREF + 0x1e,0x84,0x84, // CONTROL SACLK_ON=1 + 0x1b,0xff,0xc8, // ADC TWOS=1 + 0x3b,0xff,0xff, // IFMAX + 0x3c,0xff,0x00, // IFMIN + 0x34,0xff,0x00, // PWMREF + 0x35,0xff,0xff, // TUNMAX + 0x36,0xff,0x00, // TUNMIN + 0x06,0xff,0x7f, // EQCONF1 POSI=7 ENADAPT=ENEQUAL=DFE=1 // 0x77 + 0x1c,0x30,0x30, // EQCONF2 STEPALGO=SGNALGO=1 + 0x37,0xff,0xf6, // DELTAF_LSB + 0x38,0xff,0xff, // DELTAF_MSB + 0x02,0xff,0x93, // AGCCONF1 IFS=1 KAGCIF=2 KAGCTUN=3 + 0x2d,0xff,0xf6, // SWEEP SWPOS=1 SWDYN=7 SWSTEP=1 SWLEN=2 + 0x04,0x10,0x00, // SWRAMP=1 + 0x12,0xff,0xa1, // INTP1 POCLKP=1 FEL=1 MFS=0 + 0x2b,0x01,0xa1, // INTS1 + 0x20,0xff,0x04, // INTP2 SWAPP=? MSBFIRSTP=? INTPSEL=? + 0x2c,0xff,0x0d, // INTP/S TRIP=0 TRIS=0 + 0xc4,0xff,0x00, + 0xc3,0x30,0x00, + 0xb5,0xff,0x19, // ERAGC_THD + 0x00,0x03,0x01, // GPR, CLBS soft reset + 0x00,0x03,0x03, // GPR, CLBS soft reset + 0xff,0x64,0x00, // Sleep 100ms + 0xff,0xff,0xff +}; + +static u8 tda10023_readreg (struct tda10023_state* state, u8 reg) +{ + u8 b0 [] = { reg }; + u8 b1 [] = { 0 }; + struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 }, + { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } }; + int ret; + + ret = i2c_transfer (state->i2c, msg, 2); + if (ret != 2) + printk("DVB: TDA10023: %s: readreg error (ret == %i)\n", + __FUNCTION__, ret); + return b1[0]; +} + +static int tda10023_writereg (struct tda10023_state* state, u8 reg, u8 data) +{ + u8 buf[] = { reg, data }; + struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 }; + int ret; + + ret = i2c_transfer (state->i2c, &msg, 1); + if (ret != 1) + printk("DVB: TDA10023(%d): %s, writereg error " + "(reg == 0x%02x, val == 0x%02x, ret == %i)\n", + state->frontend.dvb->num, __FUNCTION__, reg, data, ret); + + return (ret != 1) ? -EREMOTEIO : 0; +} + + +static int tda10023_writebit (struct tda10023_state* state, u8 reg, u8 mask,u8 data) +{ + if (mask==0xff) + return tda10023_writereg(state, reg, data); + else { + u8 val; + val=tda10023_readreg(state,reg); + val&=~mask; + val|=(data&mask); + return tda10023_writereg(state, reg, val); + } +} + +static void tda10023_writetab(struct tda10023_state* state, u8* tab) +{ + u8 r,m,v; + while (1) { + r=*tab++; + m=*tab++; + v=*tab++; + if (r==0xff) { + if (m==0xff) + break; + else + msleep(m); + } + else + tda10023_writebit(state,r,m,v); + } +} + +//get access to tuner +static int lock_tuner(struct tda10023_state* state) +{ + u8 buf[2] = { 0x0f, 0xc0 }; + struct i2c_msg msg = {.addr=state->config->demod_address, .flags=0, .buf=buf, .len=2}; + + if(i2c_transfer(state->i2c, &msg, 1) != 1) + { + printk("tda10023: lock tuner fails\n"); + return -EREMOTEIO; + } + return 0; +} + +//release access from tuner +static int unlock_tuner(struct tda10023_state* state) +{ + u8 buf[2] = { 0x0f, 0x40 }; + struct i2c_msg msg_post={.addr=state->config->demod_address, .flags=0, .buf=buf, .len=2}; + + if(i2c_transfer(state->i2c, &msg_post, 1) != 1) + { + printk("tda10023: unlock tuner fails\n"); + return -EREMOTEIO; + } + return 0; +} + +static int tda10023_setup_reg0 (struct tda10023_state* state, u8 reg0) +{ + reg0 |= state->reg0 & 0x63; + + tda10023_writereg (state, 0x00, reg0 & 0xfe); + tda10023_writereg (state, 0x00, reg0 | 0x01); + + state->reg0 = reg0; + return 0; +} + +static int tda10023_set_symbolrate (struct tda10023_state* state, u32 sr) +{ + s32 BDR; + s32 BDRI; + s16 SFIL=0; + u16 NDEC = 0; + + if (sr > (SYSCLK/(2*4))) + sr=SYSCLK/(2*4); + + if (sr<870000) + sr=870000; + + if (sr < (u32)(SYSCLK/98.40)) { + NDEC=3; + SFIL=1; + } else if (sr<(u32)(SYSCLK/64.0)) { + NDEC=3; + SFIL=0; + } else if (sr<(u32)(SYSCLK/49.2)) { + NDEC=2; + SFIL=1; + } else if (sr<(u32)(SYSCLK/32.0)) { + NDEC=2; + SFIL=0; + } else if (sr<(u32)(SYSCLK/24.6)) { + NDEC=1; + SFIL=1; + } else if (sr<(u32)(SYSCLK/16.0)) { + NDEC=1; + SFIL=0; + } else if (sr<(u32)(SYSCLK/12.3)) { + NDEC=0; + SFIL=1; + } + + BDRI=SYSCLK*16; + BDRI>>=NDEC; + BDRI +=sr/2; + BDRI /=sr; + + if (BDRI>255) + BDRI=255; + + { + u64 BDRX; + + BDRX=1<<(24+NDEC); + BDRX*=sr; + do_div(BDRX,SYSCLK); // BDRX/=SYSCLK; + + BDR=(s32)BDRX; + } +// printk("Symbolrate %i, BDR %i BDRI %i, NDEC %i\n",sr,BDR,BDRI,NDEC); + tda10023_writebit (state, 0x03, 0xc0, NDEC<<6); + tda10023_writereg (state, 0x0a, BDR&255); + tda10023_writereg (state, 0x0b, (BDR>>8)&255); + tda10023_writereg (state, 0x0c, (BDR>>16)&31); + tda10023_writereg (state, 0x0d, BDRI); + tda10023_writereg (state, 0x3d, (SFIL<<7)); + return 0; +} + +static int tda10023_init (struct dvb_frontend *fe) +{ + struct tda10023_state* state = fe->demodulator_priv; + + dprintk("DVB: TDA10023(%d): init chip\n", fe->adapter->num); + + tda10023_writetab(state, tda10023_inittab); + + return 0; +} + +static int tda10023_set_parameters (struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) +{ + struct tda10023_state* state = fe->demodulator_priv; + + static int qamvals[6][6] = { + // QAM LOCKTHR MSETH AREF AGCREFNYQ ERAGCNYQ_THD + { (5<<2), 0x78, 0x8c, 0x96, 0x78, 0x4c }, // 4 QAM + { (0<<2), 0x87, 0xa2, 0x91, 0x8c, 0x57 }, // 16 QAM + { (1<<2), 0x64, 0x74, 0x96, 0x8c, 0x57 }, // 32 QAM + { (2<<2), 0x46, 0x43, 0x6a, 0x6a, 0x44 }, // 64 QAM + { (3<<2), 0x36, 0x34, 0x7e, 0x78, 0x4c }, // 128 QAM + { (4<<2), 0x26, 0x23, 0x6c, 0x5c, 0x3c }, // 256 QAM + }; + + int qam = p->u.qam.modulation; + + if (qam < 0 || qam > 5) + return -EINVAL; + + if (fe->ops.tuner_ops.set_params) { + fe->ops.tuner_ops.set_params(fe, p); + if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); + } + + tda10023_set_symbolrate (state, p->u.qam.symbol_rate); + tda10023_writereg (state, 0x05, qamvals[qam][1]); + tda10023_writereg (state, 0x08, qamvals[qam][2]); + tda10023_writereg (state, 0x09, qamvals[qam][3]); + tda10023_writereg (state, 0xb4, qamvals[qam][4]); + tda10023_writereg (state, 0xb6, qamvals[qam][5]); + +// tda10023_writereg (state, 0x04, (p->inversion?0x12:0x32)); +// tda10023_writebit (state, 0x04, 0x60, (p->inversion?0:0x20)); + tda10023_writebit (state, 0x04, 0x40, 0x40); + tda10023_setup_reg0 (state, qamvals[qam][0]); + + return 0; +} + +static int tda10023_read_status(struct dvb_frontend* fe, fe_status_t* status) +{ + struct tda10023_state* state = fe->demodulator_priv; + int sync; + + *status = 0; + + //0x11[1] == CARLOCK -> Carrier locked + //0x11[2] == FSYNC -> Frame synchronisation + //0x11[3] == FEL -> Front End locked + //0x11[6] == NODVB -> DVB Mode Information + sync = tda10023_readreg (state, 0x11); + + if (sync & 2) + *status |= FE_HAS_SIGNAL|FE_HAS_CARRIER; + + if (sync & 4) + *status |= FE_HAS_SYNC|FE_HAS_VITERBI; + + if (sync & 8) + *status |= FE_HAS_LOCK; + + return 0; +} + +static int tda10023_read_ber(struct dvb_frontend* fe, u32* ber) +{ + struct tda10023_state* state = fe->demodulator_priv; + u8 a,b,c; + a=tda10023_readreg(state, 0x14); + b=tda10023_readreg(state, 0x15); + c=tda10023_readreg(state, 0x16)&0xf; + tda10023_writebit (state, 0x10, 0xc0, 0x00); + + *ber = a | (b<<8)| (c<<16); + return 0; +} + +static int tda10023_read_signal_strength(struct dvb_frontend* fe, u16* strength) +{ + struct tda10023_state* state = fe->demodulator_priv; + u8 ifgain=tda10023_readreg(state, 0x2f); + + u16 gain = ((255-tda10023_readreg(state, 0x17))) + (255-ifgain)/16; + // Max raw value is about 0xb0 -> Normalize to >0xf0 after 0x90 + if (gain>0x90) + gain=gain+2*(gain-0x90); + if (gain>255) + gain=255; + + *strength = (gain<<8)|gain; + return 0; +} + +static int tda10023_read_snr(struct dvb_frontend* fe, u16* snr) +{ + struct tda10023_state* state = fe->demodulator_priv; + + u8 quality = ~tda10023_readreg(state, 0x18); + *snr = (quality << 8) | quality; + return 0; +} + +static int tda10023_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) +{ + struct tda10023_state* state = fe->demodulator_priv; + u8 a,b,c,d; + a= tda10023_readreg (state, 0x74); + b= tda10023_readreg (state, 0x75); + c= tda10023_readreg (state, 0x76); + d= tda10023_readreg (state, 0x77); + *ucblocks = a | (b<<8)|(c<<16)|(d<<24); + + tda10023_writebit (state, 0x10, 0x20,0x00); + tda10023_writebit (state, 0x10, 0x20,0x20); + tda10023_writebit (state, 0x13, 0x01, 0x00); + + return 0; +} + +static int tda10023_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +{ + struct tda10023_state* state = fe->demodulator_priv; + int sync,inv; + s8 afc = 0; + + sync = tda10023_readreg(state, 0x11); + afc = tda10023_readreg(state, 0x19); + inv = tda10023_readreg(state, 0x04); + + if (verbose) { + /* AFC only valid when carrier has been recovered */ + printk(sync & 2 ? "DVB: TDA10023(%d): AFC (%d) %dHz\n" : + "DVB: TDA10023(%d): [AFC (%d) %dHz]\n", + state->frontend.dvb->num, afc, + -((s32)p->u.qam.symbol_rate * afc) >> 10); + } + + p->inversion = (inv&0x20?0:1); + p->u.qam.modulation = ((state->reg0 >> 2) & 7) + QAM_16; + + p->u.qam.fec_inner = FEC_NONE; + p->frequency = ((p->frequency + 31250) / 62500) * 62500; + + if (sync & 2) + p->frequency -= ((s32)p->u.qam.symbol_rate * afc) >> 10; + + return 0; +} + +static int tda10023_sleep(struct dvb_frontend* fe) +{ + struct tda10023_state* state = fe->demodulator_priv; + + tda10023_writereg (state, 0x1b, 0x02); /* pdown ADC */ + tda10023_writereg (state, 0x00, 0x80); /* standby */ + + return 0; +} + +static int tda10023_i2c_gate_ctrl(struct dvb_frontend* fe, int enable) +{ + struct tda10023_state* state = fe->demodulator_priv; + + if (enable) { + lock_tuner(state); + } else { + unlock_tuner(state); + } + return 0; +} + +static void tda10023_release(struct dvb_frontend* fe) +{ + struct tda10023_state* state = fe->demodulator_priv; + kfree(state); +} + +static struct dvb_frontend_ops tda10023_ops; + +struct dvb_frontend* tda10023_attach(const struct tda1002x_config* config, + struct i2c_adapter* i2c, + u8 pwm) +{ + struct tda10023_state* state = NULL; + int i; + + /* allocate memory for the internal state */ + state = kmalloc(sizeof(struct tda10023_state), GFP_KERNEL); + if (state == NULL) goto error; + + /* setup the state */ + state->config = config; + state->i2c = i2c; + memcpy(&state->frontend.ops, &tda10023_ops, sizeof(struct dvb_frontend_ops)); + state->pwm = pwm; + for (i=0; i < sizeof(tda10023_inittab)/sizeof(*tda10023_inittab);i+=3) { + if (tda10023_inittab[i] == 0x00) { + state->reg0 = tda10023_inittab[i+2]; + break; + } + } + + // Wakeup if in standby + tda10023_writereg (state, 0x00, 0x33); + /* check if the demod is there */ + if ((tda10023_readreg(state, 0x1a) & 0xf0) != 0x70) goto error; + + /* create dvb_frontend */ + memcpy(&state->frontend.ops, &tda10023_ops, sizeof(struct dvb_frontend_ops)); + state->frontend.demodulator_priv = state; + return &state->frontend; + +error: + kfree(state); + return NULL; +} + +static struct dvb_frontend_ops tda10023_ops = { + + .info = { + .name = "Philips TDA10023 DVB-C", + .type = FE_QAM, + .frequency_stepsize = 62500, + .frequency_min = 51000000, + .frequency_max = 858000000, + .symbol_rate_min = (SYSCLK/2)/64, /* SACLK/64 == (SYSCLK/2)/64 */ + .symbol_rate_max = (SYSCLK/2)/4, /* SACLK/4 */ + .caps = 0x400 | //FE_CAN_QAM_4 + FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 | + FE_CAN_QAM_128 | FE_CAN_QAM_256 | + FE_CAN_FEC_AUTO + }, + + .release = tda10023_release, + + .init = tda10023_init, + .sleep = tda10023_sleep, + .i2c_gate_ctrl = tda10023_i2c_gate_ctrl, + + .set_frontend = tda10023_set_parameters, + .get_frontend = tda10023_get_frontend, + + .read_status = tda10023_read_status, + .read_ber = tda10023_read_ber, + .read_signal_strength = tda10023_read_signal_strength, + .read_snr = tda10023_read_snr, + .read_ucblocks = tda10023_read_ucblocks, +}; + + +MODULE_DESCRIPTION("Philips TDA10023 DVB-C demodulator driver"); +MODULE_AUTHOR("Georg Acher, Hartmut Birr"); +MODULE_LICENSE("GPL"); + +EXPORT_SYMBOL(tda10023_attach); diff --git a/drivers/media/dvb/frontends/tda10021.h b/drivers/media/dvb/frontends/tda1002x.h index e3da780108f6..e9094d8123f6 100644 --- a/drivers/media/dvb/frontends/tda10021.h +++ b/drivers/media/dvb/frontends/tda1002x.h @@ -1,6 +1,6 @@ /* - TDA10021 - Single Chip Cable Channel Receiver driver module - used on the the Siemens DVB-C cards + TDA10021/TDA10023 - Single Chip Cable Channel Receiver driver module + used on the the Siemens DVB-C cards Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.de> Copyright (C) 2004 Markus Schulz <msc@antzsystem.de> @@ -21,22 +21,23 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#ifndef TDA10021_H -#define TDA10021_H +#ifndef TDA1002x_H +#define TDA1002x_H #include <linux/dvb/frontend.h> -struct tda10021_config +struct tda1002x_config { /* the demodulator's i2c address */ u8 demod_address; + u8 invert; }; #if defined(CONFIG_DVB_TDA10021) || (defined(CONFIG_DVB_TDA10021_MODULE) && defined(MODULE)) -extern struct dvb_frontend* tda10021_attach(const struct tda10021_config* config, +extern struct dvb_frontend* tda10021_attach(const struct tda1002x_config* config, struct i2c_adapter* i2c, u8 pwm); #else -static inline struct dvb_frontend* tda10021_attach(const struct tda10021_config* config, +static inline struct dvb_frontend* tda10021_attach(const struct tda1002x_config* config, struct i2c_adapter* i2c, u8 pwm) { printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); @@ -44,12 +45,16 @@ static inline struct dvb_frontend* tda10021_attach(const struct tda10021_config* } #endif // CONFIG_DVB_TDA10021 -static inline int tda10021_writereg(struct dvb_frontend *fe, u8 reg, u8 val) { - int r = 0; - u8 buf[] = {reg, val}; - if (fe->ops.write) - r = fe->ops.write(fe, buf, 2); - return r; +#if defined(CONFIG_DVB_TDA10023) || (defined(CONFIG_DVB_TDA10023_MODULE) && defined(MODULE)) +extern struct dvb_frontend* tda10023_attach(const struct tda1002x_config* config, + struct i2c_adapter* i2c, u8 pwm); +#else +static inline struct dvb_frontend* tda10023_attach(const struct tda1002x_config* config, + struct i2c_adapter* i2c, u8 pwm) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); + return NULL; } +#endif // CONFIG_DVB_TDA10023 -#endif // TDA10021_H +#endif // TDA1002x_H diff --git a/drivers/media/dvb/frontends/tda1004x.c b/drivers/media/dvb/frontends/tda1004x.c index f4a9cf9d26d0..33a84372c9e6 100644 --- a/drivers/media/dvb/frontends/tda1004x.c +++ b/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,35 +493,51 @@ 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; + if (state->config->request_firmware != NULL) { /* request the firmware, this will block until someone uploads it */ 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,33 @@ 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 - break; - case TDA10046_AGC_TDA827X_GP00: - 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 + tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0xf0, 0x00); // set AGC polarities break; - case TDA10046_AGC_TDA827X_GP01: + 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, 0x62); // set AGC polarities + tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0xf0, 0x60); // set AGC polarities break; } + if (state->config->ts_mode == 0) { + tda1004x_write_mask(state, TDA10046H_CONF_TRISTATE1, 0xc0, 0x40); + tda1004x_write_mask(state, 0x3a, 0x80, state->config->invert_oclk << 7); + } else { + tda1004x_write_mask(state, TDA10046H_CONF_TRISTATE1, 0xc0, 0x80); + tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0x10, + state->config->invert_oclk << 4); + } tda1004x_write_byteI(state, TDA1004X_CONFADC2, 0x38); - tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE1, 0x61); // Turn both AGC outputs on + tda1004x_write_mask (state, TDA10046H_CONF_TRISTATE1, 0x3e, 0x38); // 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); // } @@ -678,7 +676,6 @@ static int tda10046_init(struct dvb_frontend* fe) tda1004x_write_byteI(state, TDA1004X_CONF_TS1, 7); // MPEG2 interface config tda1004x_write_byteI(state, TDA1004X_CONF_TS2, 0xc0); // MPEG2 interface config // tda1004x_write_mask(state, 0x50, 0x80, 0x80); // handle out of guard echoes - tda1004x_write_mask(state, 0x3a, 0x80, state->config->invert_oclk << 7); return 0; } @@ -705,7 +702,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 +1163,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 +1173,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/drivers/media/dvb/frontends/tda1004x.h b/drivers/media/dvb/frontends/tda1004x.h index ec502d71b83c..abae84350142 100644 --- a/drivers/media/dvb/frontends/tda1004x.h +++ b/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 { @@ -47,6 +61,11 @@ enum tda10046_if { TDA10046_FREQ_052, /* low IF, 5.1667 MHZ for tda9889 */ }; +enum tda10046_tsout { + TDA10046_TS_PARALLEL = 0x00, /* parallel transport stream, default */ + TDA10046_TS_SERIAL = 0x01, /* serial transport stream */ +}; + struct tda1004x_config { /* the demodulator's i2c address */ @@ -58,6 +77,9 @@ struct tda1004x_config /* Does the OCLK signal need inverted? */ u8 invert_oclk; + /* parallel or serial transport stream */ + enum tda10046_tsout ts_mode; + /* Xtal frequency, 4 or 16MHz*/ enum tda10046_xtal xtal_freq; @@ -67,11 +89,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/drivers/media/dvb/frontends/tda827x.c b/drivers/media/dvb/frontends/tda827x.c new file mode 100644 index 000000000000..256fc4bf500b --- /dev/null +++ b/drivers/media/dvb/frontends/tda827x.c @@ -0,0 +1,512 @@ +/* + * + * (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; + + dprintk("%s:\n", __FUNCTION__); + 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) }; + + dprintk("%s:\n", __FUNCTION__); + 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; + + dprintk("%s:\n", __FUNCTION__); + 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) }; + + dprintk("%s:\n", __FUNCTION__); + 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; + dprintk("%s:\n", __FUNCTION__); + if (priv->cfg && priv->cfg->init) + priv->cfg->init(fe); + + return 0; +} + +static int tda827x_probe_version(struct dvb_frontend *fe); + +static int tda827x_initial_init(struct dvb_frontend *fe) +{ + int ret; + ret = tda827x_probe_version(fe); + if (ret) + return ret; + return fe->ops.tuner_ops.init(fe); +} + +static int tda827x_initial_sleep(struct dvb_frontend *fe) +{ + int ret; + ret = tda827x_probe_version(fe); + if (ret) + return ret; + return fe->ops.tuner_ops.sleep(fe); +} + +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_initial_init, + .sleep = tda827x_initial_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, +}; + +static int tda827x_probe_version(struct dvb_frontend *fe) +{ u8 data; + struct tda827x_priv *priv = fe->tuner_priv; + struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = I2C_M_RD, + .buf = &data, .len = 1 }; + 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 read from tuner at addr: 0x%02x\n", + __FUNCTION__, msg.addr << 1); + return -EIO; + } + if ((data & 0x3c) == 0) { + dprintk("tda827x tuner found\n"); + fe->ops.tuner_ops.init = tda827x_init; + fe->ops.tuner_ops.sleep = tda827xo_sleep; + } else { + dprintk("tda827xa tuner found\n"); + memcpy(&fe->ops.tuner_ops, &tda827xa_tuner_ops, sizeof(struct dvb_tuner_ops)); + } + return 0; +} + +struct dvb_frontend *tda827x_attach(struct dvb_frontend *fe, int addr, + struct i2c_adapter *i2c, + struct tda827x_config *cfg) +{ + struct tda827x_priv *priv = NULL; + + dprintk("%s:\n", __FUNCTION__); + priv = kzalloc(sizeof(struct tda827x_priv), GFP_KERNEL); + if (priv == NULL) + return NULL; + + priv->i2c_addr = addr; + priv->i2c_adap = i2c; + priv->cfg = cfg; + memcpy(&fe->ops.tuner_ops, &tda827xo_tuner_ops, sizeof(struct dvb_tuner_ops)); + + fe->tuner_priv = priv; + + 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/drivers/media/dvb/frontends/tda827x.h b/drivers/media/dvb/frontends/tda827x.h new file mode 100644 index 000000000000..69e8263d6d59 --- /dev/null +++ b/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__ |