Hi,
>> It seems that Reelbox
>> (http://www.reel-multimedia.co.uk/reelbox-software.html) does indeed
>> contain some sort of GPL-driver for TDA10023. I checked out the ReelBox
> <...>
>
> Some sort? It's GPL. The reason why it is stil based on the DVB-API of
> 2.6.12 is that there were too many API changes in the last time
> (especially
Uh, I did not mean to imply anything about your drivers license. I more or
less meant that the driver in ReelBox-repo is for an unknown card using
the TDA10023 frontend which might not be 1:1 compatible with Terratec
and/or Satelco etc.
> the PLL stuff) and with the upcomming S2 I currently don't see any
> stabilisation in the near future. As the drivers works fine for the RB,
> there's no need to waste time in continuously porting to the current API
> ;-)
Anyway, it's great to see that your driver has been licensed in GPL and I
thank you for doing it :)
>> #>scan -a 2 fi-elisa
>> scanning fi-elisa
>> using '/dev/dvb/adapter2/frontend0' and '/dev/dvb/adapter2/demux0'
>> initial transponder 154000000 6900000 0 4
>> initial transponder 370000000 6900000 0 4
>> >>> tune to: 154000000:INVERSION_AUTO:6900000:FEC_NONE:QAM_128
>
> First try with czap that you're actually getting a lock.
I neglected to mention that getting a lock seems to work without problems.
#>czap -a 2 MTV3
using '/dev/dvb/adapter2/frontend0' and '/dev/dvb/adapter2/demux0'
1 MTV3:154000000:INVERSION_AUTO:6900000:FEC_NONE:QAM_128:305:561:49
1 MTV3: f 154000000, s 6900000, i 2, fec 0, qam 4, v 0x131, a 0x231
status 00 | signal aeae | snr a3a3 | ber 000fffff | unc 00000034 |
status 1f | signal eaea | snr f4f4 | ber 000005e8 | unc 000001c5 |
FE_HAS_LOCK
status 1f | signal eaea | snr f4f4 | ber 00000000 | unc 00000000 |
FE_HAS_LOCK
status 1f | signal eaea | snr f4f4 | ber 00000000 | unc 00000000 |
FE_HAS_LOCK
status 1f | signal eaea | snr f5f5 | ber 00000000 | unc 00000000 |
FE_HAS_LOCK
status 1f | signal eaea | snr f5f5 | ber 00000000 | unc 00000000 |
FE_HAS_LOCK
>> WARNING: filter timeout pid 0x0011
>
> Maybe the parallel data output configuration is wrong and the data is
> latched at the wrong edge. The value is in the inittab, adress 0x12. The
> clock polarity is bit 0, so a change to 0xa1 would be worth a try.
I changed the inittab line:
0x12,0xff,0xa0, // INTP1 POCLKP=1 FEL=1 MFS=0
to
0x12,0xff,0xa1, // INTP1 POCLKP=1 FEL=1 MFS=0
but without success. It might of course be that the I've made an obvious
mistake in merging the driver with the 2.6.20-rc7 kernel version.
I did enable some debug printk's in the driver and got the following
interesting printouts:
Feb 2 07:49:40 valen kernel: Symbolrate 6900000, BDR 2001431 BDRI 134,
NDEC 0
Feb 2 07:49:40 valen kernel: DVB: TDA10023(2): AFC (-1) 6738Hz
I compared the AFC-values to another Hauppauge/Technotrend DVB-C 1.0 card
and it gives the following AFC-values (in case that give's you some hints
about the problem):
Feb 2 01:29:38 valen kernel: DVB: registering frontend 1 (VLSI VES1820
DVB-C)...
Feb 2 01:30:57 valen kernel: ves1820: AFC (3) -20215Hz
Feb 2 01:30:58 valen kernel: ves1820: AFC (3) -20215Hz
Feb 2 01:31:21 valen kernel: ves1820: AFC (4) -26954Hz
Feb 2 01:31:23 valen kernel: ves1820: AFC (5) -33692Hz
>
>> PS. It would be so much easier with proper programming docs ... :(
>
> I have the data sheet, but I don't know the current status of it. As NXP
> still doesn't have it on their webpage, I assume it's on purpose.
I did ask for the programming specs for the TDA10023 from nxp.com but got
an email saying that document is not available for public. They suggested
asking from card manufacturer ...
Sincerely,
Tomi Orava
PS. Attached is the merged driver diff I've tried to get working.
--
diff -N -u -r -x '*.ko' -x '*.d' -x '*.o' -x '*.symvers' -x '.*' -x '*.mod.c' orig/linux-2.6.20-rc7/drivers/media/dvb/frontends/Kconfig linux-2.6.20-rc7/drivers/media/dvb/frontends/Kconfig
--- orig/linux-2.6.20-rc7/drivers/media/dvb/frontends/Kconfig 2007-02-01 23:07:10.000000000 +0200
+++ linux-2.6.20-rc7/drivers/media/dvb/frontends/Kconfig 2007-02-01 23:22:16.000000000 +0200
@@ -205,6 +205,13 @@
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
diff -N -u -r -x '*.ko' -x '*.d' -x '*.o' -x '*.symvers' -x '.*' -x '*.mod.c' orig/linux-2.6.20-rc7/drivers/media/dvb/frontends/Makefile linux-2.6.20-rc7/drivers/media/dvb/frontends/Makefile
--- orig/linux-2.6.20-rc7/drivers/media/dvb/frontends/Makefile 2007-02-01 23:07:10.000000000 +0200
+++ linux-2.6.20-rc7/drivers/media/dvb/frontends/Makefile 2007-02-01 23:22:16.000000000 +0200
@@ -25,6 +25,7 @@
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
diff -N -u -r -x '*.ko' -x '*.d' -x '*.o' -x '*.symvers' -x '.*' -x '*.mod.c' orig/linux-2.6.20-rc7/drivers/media/dvb/frontends/tda10023.c linux-2.6.20-rc7/drivers/media/dvb/frontends/tda10023.c
--- orig/linux-2.6.20-rc7/drivers/media/dvb/frontends/tda10023.c 1970-01-01 02:00:00.000000000 +0200
+++ linux-2.6.20-rc7/drivers/media/dvb/frontends/tda10023.c 2007-02-02 07:51:58.000000000 +0200
@@ -0,0 +1,628 @@
+/*
+ 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)
+
+ Remotely based on tda10021.c
+ Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@xxxxxxxxxxxxxx>
+ Copyright (C) 2004 Markus Schulz <msc@xxxxxxxxxxxxx>
+ 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 "tda10023.h"
+
+
+struct tda10023_state {
+ struct i2c_adapter* i2c;
+ /* configuration settings */
+ const struct tda10023_config* config;
+ struct dvb_frontend frontend;
+
+ u8 pwm;
+ u8 reg0;
+};
+
+
+#ifdef dprintk
+#undef dprintk
+#endif
+
+#define dprintk(level,args...) \
+ do { if ((verbose & level)) { printk("%s: %s(): ", KBUILD_MODNAME, __FUNCTION__); printk(args); } } while (0)
+
+
+static int verbose;
+module_param_named(debug, verbose, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off TDA10023 debugging (default:off).");
+
+#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,0xa0, // INTP1 POCLKP=1 FEL=1 MFS=0
+ 0x2b,0x01,0xa1, // INTS1
+ 0x20,0xff,0x06, // INTP2 SWAPP=0 MSBFIRSTP=1 INTPSEL=2
+ 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, tda10023_inittab[0x0f] | 0x80 };
+ 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, tda10023_inittab[0x0f] & 0x7f };
+ struct i2c_msg msg_post={.addr=state->config->demod_address, .flags=0, .buf=buf, .len=2};
+
+ dprintk(2, "unlock_tuner() Called\n");
+
+ 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;
+}
+
+#if 0
+#define XIN 57840000UL
+#define FIN (XIN >> 4)
+
+
+static int tda10023_set_symbolrate (struct tda10023_state* state, u32 symbolrate)
+{
+ s32 BDR;
+ s32 BDRI;
+ s16 SFIL=0;
+ u16 NDEC = 0;
+ u32 tmp, ratio;
+
+ if (symbolrate > XIN/2)
+ symbolrate = XIN/2;
+ if (symbolrate < 500000)
+ symbolrate = 500000;
+
+ if (symbolrate < XIN/16) NDEC = 1;
+ if (symbolrate < XIN/32) NDEC = 2;
+ if (symbolrate < XIN/64) NDEC = 3;
+
+ if (symbolrate < (u32)(XIN/12.3)) SFIL = 1;
+ if (symbolrate < (u32)(XIN/16)) SFIL = 0;
+ if (symbolrate < (u32)(XIN/24.6)) SFIL = 1;
+ if (symbolrate < (u32)(XIN/32)) SFIL = 0;
+ if (symbolrate < (u32)(XIN/49.2)) SFIL = 1;
+ if (symbolrate < (u32)(XIN/64)) SFIL = 0;
+ if (symbolrate < (u32)(XIN/98.4)) SFIL = 1;
+
+ symbolrate <<= NDEC;
+ ratio = (symbolrate << 4) / FIN;
+ tmp = ((symbolrate << 4) % FIN) << 8;
+ ratio = (ratio << 8) + tmp / FIN;
+ tmp = (tmp % FIN) << 8;
+ ratio = (ratio << 8) + (tmp + FIN/2) / FIN;
+
+ BDR = ratio;
+ BDRI = (((XIN << 5) / symbolrate) + 1) / 2;
+
+ if (BDRI > 0xFF)
+ BDRI = 0xFF;
+
+ SFIL = (SFIL << 4) | tda10023_inittab[0x0E];
+
+ NDEC = (NDEC << 6) | tda10023_inittab[0x03];
+ tda10023_writereg (state, 0x03, NDEC);
+ tda10023_writereg (state, 0x0a, BDR&0xff);
+ tda10023_writereg (state, 0x0b, (BDR>> 8)&0xff);
+ tda10023_writereg (state, 0x0c, (BDR>>16)&0x3f);
+
+ tda10023_writereg (state, 0x0d, BDRI);
+ tda10023_writereg (state, 0x0e, SFIL);
+
+ return 0;
+}
+#endif
+
+int tda10023_write(struct dvb_frontend* fe, u8 *buf, int len)
+{
+ struct tda10023_state* state = fe->demodulator_priv;
+ if (len != 2)
+ return -EINVAL;
+
+ return tda10023_writereg(state, buf[0], buf[1]);
+}
+
+static int tda10023_init (struct dvb_frontend *fe)
+{
+ struct tda10023_state* state = fe->demodulator_priv;
+
+ dprintk(2, "DVB: TDA10023(%d): init chip\n", fe->dvb->num);
+
+ tda10023_writetab(state, tda10023_inittab);
+
+// if (state->config->pll_init) {
+// lock_tuner(state);
+// state->config->pll_init(fe);
+// unlock_tuner(state);
+// }
+
+ 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
+ { 0x14, 0x78, 0x8c, 0x96, 0x78, 0x4c }, // 4 QAM
+ { 0x00, 0x87, 0xa2, 0x91, 0x8c, 0x57 }, // 16 QAM
+ { 0x04, 0x64, 0x74, 0x96, 0x8c, 0x57 }, // 32 QAM
+ { 0x08, 0x46, 0x43, 0x6a, 0x6a, 0x44 }, // 64 QAM
+ { 0x0c, 0x36, 0x34, 0x7e, 0x78, 0x4c }, // 128 QAM
+ { 0x10, 0x26, 0x23, 0x6c, 0x5c, 0x3c }, // 256 QAM
+ };
+
+ int qam = p->u.qam.modulation;
+
+ if (qam < 0 || qam > 5)
+ return -EINVAL;
+
+// lock_tuner(state);
+// state->config->pll_set(fe, p);
+// unlock_tuner(state);
+
+ 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;
+
+ printk("tda10023_get_frontend() Called\n");
+
+ 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 tda10023_config* config,
+ struct i2c_adapter* i2c,
+ u8 pwm)
+{
+ struct tda10023_state* state = NULL;
+
+ /* 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;
+ state->reg0 = tda10023_inittab[0]; // 0x73; // FIXME!!!
+
+ // 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.ops = &state->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 = (57840000UL/2)/64, /* SACLK/64 == (SYSCLK/2)/64 */
+ .symbol_rate_max = (57840000UL/2)/4, /* SACLK/4 */
+ #if 0
+ .frequency_tolerance = ???,
+ .symbol_rate_tolerance = ???, /* ppm */ /* == 8% (spec p. 5) */
+ #endif
+ .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,
+ .write = tda10023_write,
+ .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");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(tda10023_attach);
diff -N -u -r -x '*.ko' -x '*.d' -x '*.o' -x '*.symvers' -x '.*' -x '*.mod.c' orig/linux-2.6.20-rc7/drivers/media/dvb/frontends/tda10023.h linux-2.6.20-rc7/drivers/media/dvb/frontends/tda10023.h
--- orig/linux-2.6.20-rc7/drivers/media/dvb/frontends/tda10023.h 1970-01-01 02:00:00.000000000 +0200
+++ linux-2.6.20-rc7/drivers/media/dvb/frontends/tda10023.h 2007-02-01 23:40:10.000000000 +0200
@@ -0,0 +1,50 @@
+/*
+ TDA10023 - DVB-C decoder (as used in Philips CU1216-3 NIM)
+
+ Copyright (C) 2005 Georg Acher, BayCom GmbH (acher at baycom dot de)
+
+ Based on tda10021.c
+ Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@xxxxxxxxxxxxxx>
+ Copyright (C) 2004 Markus Schulz <msc@xxxxxxxxxxxxx>
+ 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.
+
+*/
+
+#ifndef TDA10023_H
+#define TDA10023_H
+
+#include <linux/dvb/frontend.h>
+
+struct tda10023_config
+{
+ /* the demodulator's i2c address */
+ u8 demod_address;
+};
+
+#if defined(CONFIG_DVB_TDA10023) || (defined(CONFIG_DVB_TDA10023_MODULE) && defined(MODULE))
+extern struct dvb_frontend* tda10023_attach(const struct tda10023_config* config,
+ struct i2c_adapter* i2c, u8 pwm);
+#else
+static inline struct dvb_frontend* tda10023_attach(const struct tda10023_config* config,
+ struct i2c_adapter* i2c, u8 pwm)
+{
+ printk(KRNL_WARNING "%s: driver disabled byKconfig\n", __FUNCTION__);
+ return NULL;
+}
+#endif // CONFIG_DVB_TDA10023
+
+#endif // TDA10023_H
diff -N -u -r -x '*.ko' -x '*.d' -x '*.o' -x '*.symvers' -x '.*' -x '*.mod.c' orig/linux-2.6.20-rc7/drivers/media/dvb/ttpci/budget-av.c linux-2.6.20-rc7/drivers/media/dvb/ttpci/budget-av.c
--- orig/linux-2.6.20-rc7/drivers/media/dvb/ttpci/budget-av.c 2007-02-01 23:07:10.000000000 +0200
+++ linux-2.6.20-rc7/drivers/media/dvb/ttpci/budget-av.c 2007-02-02 01:12:53.000000000 +0200
@@ -36,6 +36,7 @@
#include "budget.h"
#include "stv0299.h"
#include "tda10021.h"
+#include "tda10023.h"
#include "tda1004x.h"
#include "tua6100.h"
#include "dvb-pll.h"
@@ -74,6 +75,12 @@
static int ciintf_slot_shutdown(struct dvb_ca_en50221 *ca, int slot);
+static int debug;
+module_param(debug, int, 0444);
+MODULE_PARM_DESC(debug, "Turn on/off budget-av debugging (default:off).");
+
+
+
/* GPIO Connections:
* 0 - Vcc/Reset (Reset is controlled by capacitor). Resets the frontend *AS WELL*!
* 1 - CI memory select 0=>IO memory, 1=>Attribute Memory
@@ -651,10 +658,40 @@
return 0;
}
+static int philips_cu1216_mk3_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+{
+ struct budget *budget = (struct budget *) fe->dvb->priv;
+ u8 buf[6];
+ struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = buf,.len = sizeof(buf) };
+
+#define CU1216_IF 36125000
+#define TUNER_MUL 62500
+
+ u32 div = (params->frequency + CU1216_IF + TUNER_MUL / 2) / TUNER_MUL;
+
+ buf[0] = (div >> 8) & 0x7f;
+ buf[1] = div & 0xff;
+ buf[2] = 0xce;
+ buf[3] = (params->frequency < (160000000+ CU1216_IF) ? 0x01 :
+ params->frequency >= (445000000+CU1216_IF) ? 0x04
+ : 0x02);
+ buf[4] = 0xde;
+ buf[5] = 0x20;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1)
+ return -EIO;
+ return 0;
+}
+
static struct tda10021_config philips_cu1216_config = {
.demod_address = 0x0c,
};
+static struct tda10023_config philips_cu1216_mk3_config = {
+ .demod_address = 0x0c,
+};
static struct tda10021_config philips_cu1216_config_altaddress = {
.demod_address = 0x0d,
};
@@ -908,6 +945,14 @@
return pwm;
}
+static u8 tda10023_read_pwm(struct budget_av *budget_av)
+{
+ u8 pwm;
+ pwm = 0x48;
+
+ return pwm;
+}
+
#define SUBID_DVBS_KNC1 0x0010
#define SUBID_DVBS_KNC1_PLUS 0x0011
#define SUBID_DVBS_TYPHOON 0x4f56
@@ -919,9 +964,11 @@
#define SUBID_DVBS_EASYWATCH_1 0x001a
#define SUBID_DVBS_EASYWATCH 0x001e
#define SUBID_DVBC_EASYWATCH 0x002a
+#define SUBID_DVBC_EASYWATCH_MK3 0x002c
#define SUBID_DVBC_KNC1 0x0020
#define SUBID_DVBC_KNC1_PLUS 0x0021
#define SUBID_DVBC_CINERGY1200 0x1156
+#define SUBID_DVBC_CINERGY1200_MK3 0x1176
#define SUBID_DVBT_KNC1_PLUS 0x0031
#define SUBID_DVBT_KNC1 0x0030
@@ -944,6 +991,22 @@
return result;
}
+static int tda10023_set_frontend(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *p)
+{
+ struct budget_av* budget_av = fe->dvb->priv;
+ int result;
+
+ result = budget_av->tda10021_set_frontend(fe, p);
+ if (budget_av->tda10021_ts_enabled) {
+ tda10021_writereg(budget_av->budget.dvb_frontend, 0x12, 0xa1);
+ } else {
+ tda10021_writereg(budget_av->budget.dvb_frontend, 0x12, 0xa0);
+ }
+
+ return result;
+}
+
static void frontend_init(struct budget_av *budget_av)
{
struct saa7146_dev * saa = budget_av->budget.dev;
@@ -1032,6 +1095,20 @@
}
break;
+ case SUBID_DVBC_CINERGY1200_MK3:
+ case SUBID_DVBC_EASYWATCH_MK3:
+ budget_av->reinitialise_demod = 1;
+ fe = dvb_attach(tda10023_attach, &philips_cu1216_mk3_config,
+ &budget_av->budget.i2c_adap,
+ read_pwm(budget_av));
+ if (fe) {
+ budget_av->tda10021_poclkp = 1;
+ budget_av->tda10021_set_frontend = fe->ops.set_frontend;
+ fe->ops.set_frontend = tda10023_set_frontend;
+ fe->ops.tuner_ops.set_params = philips_cu1216_mk3_tuner_set_params;
+ }
+ break;
+
case SUBID_DVBT_KNC1:
case SUBID_DVBT_KNC1_PLUS:
case SUBID_DVBT_CINERGY1200:
@@ -1257,6 +1334,7 @@
MAKE_BUDGET_INFO(satewpls, "Satelco EasyWatch DVB-S light", BUDGET_TVSTAR);
MAKE_BUDGET_INFO(satewpls1, "Satelco EasyWatch DVB-S light", BUDGET_KNC1S);
MAKE_BUDGET_INFO(satewplc, "Satelco EasyWatch DVB-C", BUDGET_KNC1CP);
+MAKE_BUDGET_INFO(satewplcmk3, "Satelco EasyWatch DVB-C MK3", BUDGET_KNC1CP);
MAKE_BUDGET_INFO(knc1sp, "KNC1 DVB-S Plus", BUDGET_KNC1SP);
MAKE_BUDGET_INFO(knc1cp, "KNC1 DVB-C Plus", BUDGET_KNC1CP);
MAKE_BUDGET_INFO(knc1tp, "KNC1 DVB-T Plus", BUDGET_KNC1TP);
@@ -1276,6 +1354,7 @@
MAKE_EXTENSION_PCI(satewpls, 0x1894, 0x001e),
MAKE_EXTENSION_PCI(satewpls1, 0x1894, 0x001a),
MAKE_EXTENSION_PCI(satewplc, 0x1894, 0x002a),
+ MAKE_EXTENSION_PCI(satewplcmk3, 0x1894, 0x002c),
MAKE_EXTENSION_PCI(knc1c, 0x1894, 0x0020),
MAKE_EXTENSION_PCI(knc1cp, 0x1894, 0x0021),
MAKE_EXTENSION_PCI(knc1t, 0x1894, 0x0030),
diff -N -u -r -x '*.ko' -x '*.d' -x '*.o' -x '*.symvers' -x '.*' -x '*.mod.c' orig/linux-2.6.20-rc7/drivers/media/dvb/ttpci/Kconfig linux-2.6.20-rc7/drivers/media/dvb/ttpci/Kconfig
--- orig/linux-2.6.20-rc7/drivers/media/dvb/ttpci/Kconfig 2007-02-01 23:07:10.000000000 +0200
+++ linux-2.6.20-rc7/drivers/media/dvb/ttpci/Kconfig 2007-02-01 23:22:16.000000000 +0200
@@ -69,6 +69,7 @@
select DVB_L64781 if !DVB_FE_CUSTOMISE
select DVB_TDA8083 if !DVB_FE_CUSTOMISE
select DVB_TDA10021 if !DVB_FE_CUSTOMISE
+ select DVB_TDA10023 if !DVB_FE_CUSTOMISE
select DVB_S5H1420 if !DVB_FE_CUSTOMISE
select DVB_TDA10086 if !DVB_FE_CUSTOMISE
select DVB_TDA826X if !DVB_FE_CUSTOMISE
@@ -114,6 +115,7 @@
select DVB_STV0299 if !DVB_FE_CUSTOMISE
select DVB_TDA1004X if !DVB_FE_CUSTOMISE
select DVB_TDA10021 if !DVB_FE_CUSTOMISE
+ select DVB_TDA10023 if !DVB_FE_CUSTOMISE
select DVB_TUA6100 if !DVB_FE_CUSTOMISE
select FW_LOADER
help
_______________________________________________
linux-dvb mailing list
linux-dvb@xxxxxxxxxxx
http://www.linuxtv.org/cgi-bin/mailman/listinfo/linux-dvb