diff options
Diffstat (limited to 'linux/drivers/media/dvb/frontends/stv0299.c')
-rw-r--r-- | linux/drivers/media/dvb/frontends/stv0299.c | 205 |
1 files changed, 162 insertions, 43 deletions
diff --git a/linux/drivers/media/dvb/frontends/stv0299.c b/linux/drivers/media/dvb/frontends/stv0299.c index 927099865..18ecc1030 100644 --- a/linux/drivers/media/dvb/frontends/stv0299.c +++ b/linux/drivers/media/dvb/frontends/stv0299.c @@ -19,6 +19,12 @@ Copyright (C) 2002 Felix Domke <tmbinc@elitedvb.net> & Andreas Oberritter <andreas@oberritter.de> + Changelog : + + Vadim Catana <skystar@moldova.cc>: + added support for Samsung TBMU24112IMB used on Technisat SkyStar2 rev. 2.6B + + 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 @@ -39,6 +45,7 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/string.h> +#include <asm/div64.h> #include "dvb_frontend.h" #include "dvb_functions.h" @@ -51,11 +58,12 @@ /* frontend types */ -#define UNKNOWN_FRONTEND -1 -#define PHILIPS_SU1278SH 0 -#define ALPS_BSRU6 1 -#define LG_TDQF_S001F 2 -#define PHILIPS_SU1278 3 +#define UNKNOWN_FRONTEND -1 +#define PHILIPS_SU1278SH 0 +#define ALPS_BSRU6 1 +#define LG_TDQF_S001F 2 +#define PHILIPS_SU1278 3 +#define SAMSUNG_TBMU24112IMB 4 /* Master Clock = 88 MHz */ #define M_CLK (88000000UL) @@ -142,6 +150,51 @@ static u8 init_tab [] = { }; +static u8 init_tab_samsung [] = { + 0x01, 0x15, + 0x02, 0x00, + 0x03, 0x00, + 0x04, 0x7D, + 0x05, 0x35, + 0x06, 0x02, + 0x07, 0x00, + 0x08, 0xC3, + 0x0C, 0x00, + 0x0D, 0x81, + 0x0E, 0x23, + 0x0F, 0x12, + 0x10, 0x7E, + 0x11, 0x84, + 0x12, 0xB9, + 0x13, 0x88, + 0x14, 0x89, + 0x15, 0xC9, + 0x16, 0x00, + 0x17, 0x5C, + 0x18, 0x00, + 0x19, 0x00, + 0x1A, 0x00, + 0x1C, 0x00, + 0x1D, 0x00, + 0x1E, 0x00, + 0x1F, 0x3A, + 0x20, 0x2E, + 0x21, 0x80, + 0x22, 0xFF, + 0x23, 0xC1, + 0x28, 0x00, + 0x29, 0x1E, + 0x2A, 0x14, + 0x2B, 0x0F, + 0x2C, 0x09, + 0x2D, 0x05, + 0x31, 0x1F, + 0x32, 0x19, + 0x33, 0xFE, + 0x34, 0xB3 +}; + + static int stv0299_writereg (struct dvb_i2c_bus *i2c, u8 reg, u8 data) { int ret; @@ -194,18 +247,19 @@ static int stv0299_readregs (struct dvb_i2c_bus *i2c, u8 reg1, u8 *b, u8 len) static int pll_write (struct dvb_i2c_bus *i2c, u8 addr, u8 *data, int len) { int ret; - u8 rpt1 [] = { 0x05, 0xb5 }; /* enable i2c repeater on stv0299 */ - u8 rpt2 [] = { 0x05, 0x35 }; /* disable i2c repeater on stv0299 */ - struct i2c_msg msg [] = {{ .addr = 0x68, .flags = 0, .buf = rpt1, .len = 2 }, - { addr: addr, .flags = 0, .buf = data, .len = len }, - { .addr = 0x68, .flags = 0, .buf = rpt2, .len = 2 }}; + struct i2c_msg msg = { addr: addr, .flags = 0, .buf = data, .len = len }; + - ret = i2c->xfer (i2c, msg, 3); + stv0299_writereg(i2c, 0x05, 0xb5); /* enable i2c repeater on stv0299 */ - if (ret != 3) - printk("%s: i/o error (ret == %i)\n", __FUNCTION__, ret); + ret = i2c->xfer (i2c, &msg, 1); - return (ret != 3) ? ret : 0; + stv0299_writereg(i2c, 0x05, 0x35); /* disable i2c repeater on stv0299 */ + + if (ret != 1) + dprintk("%s: i/o error (ret == %i)\n", __FUNCTION__, ret); + + return (ret != 1) ? -1 : 0; } @@ -214,23 +268,16 @@ static int sl1935_set_tv_freq (struct dvb_i2c_bus *i2c, u32 freq, int ftype) u8 buf[4]; u32 div; - u32 ratios[] = { 2000, 1000, 500, 250, 125 }; - u8 ratio; - - for (ratio = 4; ratio > 0; ratio--) - if ((freq / ratios[ratio]) <= 0x3fff) - break; + div = freq / 125; - div = freq / ratios[ratio]; + dprintk("%s : freq = %i, div = %i\n", __FUNCTION__, freq, div); - buf[0] = (freq >> 8) & 0x7f; - buf[1] = freq & 0xff; - buf[2] = 0x80 | ratio; + buf[0] = (div >> 8) & 0x7f; + buf[1] = div & 0xff; + buf[2] = 0x84; // 0xC4 + buf[3] = 0x08; - if (freq < 1531000) - buf[3] = 0x10; - else - buf[3] = 0x00; + if (freq < 1500000) buf[3] |= 0x10; return pll_write (i2c, 0x61, buf, sizeof(buf)); } @@ -386,7 +433,9 @@ static int tua6100_set_tv_freq (struct dvb_i2c_bus *i2c, u32 freq, static int pll_set_tv_freq (struct dvb_i2c_bus *i2c, u32 freq, int ftype, int srate) { - if (ftype == LG_TDQF_S001F) + if (ftype == SAMSUNG_TBMU24112IMB) + return sl1935_set_tv_freq(i2c, freq, ftype); + else if (ftype == LG_TDQF_S001F) return sl1935_set_tv_freq(i2c, freq, ftype); else if (ftype == PHILIPS_SU1278) return tua6100_set_tv_freq(i2c, freq, ftype, srate); @@ -422,6 +471,20 @@ static int stv0299_init (struct dvb_i2c_bus *i2c, int ftype) dprintk("stv0299: init chip\n"); + if(ftype == SAMSUNG_TBMU24112IMB) + { + dprintk("%s: init stv0299 chip for Samsung TBMU24112IMB\n", __FUNCTION__); + + for (i=0; i<sizeof(init_tab_samsung); i+=2) + { + dprintk("%s: reg == 0x%02x, val == 0x%02x\n", __FUNCTION__, init_tab_samsung[i], init_tab_samsung[i+1]); + + stv0299_writereg (i2c, init_tab_samsung[i], init_tab_samsung[i+1]); + } + + return 0; + } + stv0299_writereg (i2c, 0x01, 0x15); stv0299_writereg (i2c, 0x02, ftype == PHILIPS_SU1278 ? 0x00 : 0x30); stv0299_writereg (i2c, 0x03, 0x00); @@ -449,6 +512,7 @@ static int stv0299_check_inversion (struct dvb_i2c_bus *i2c) dvb_delay(30); if ((stv0299_readreg (i2c, 0x1b) & 0x98) != 0x98) { u8 val = stv0299_readreg (i2c, 0x0c); + dprintk ("%s : changing inversion\n", __FUNCTION__); return stv0299_writereg (i2c, 0x0c, val ^ 0x01); } } @@ -463,20 +527,41 @@ static int stv0299_set_FEC (struct dvb_i2c_bus *i2c, fe_code_rate_t fec) switch (fec) { case FEC_AUTO: + { + dprintk ("%s : FEC_AUTO\n", __FUNCTION__); return stv0299_writereg (i2c, 0x31, 0x1f); + } case FEC_1_2: + { + dprintk ("%s : FEC_1_2\n", __FUNCTION__); return stv0299_writereg (i2c, 0x31, 0x01); + } case FEC_2_3: + { + dprintk ("%s : FEC_2_3\n", __FUNCTION__); return stv0299_writereg (i2c, 0x31, 0x02); + } case FEC_3_4: + { + dprintk ("%s : FEC_3_4\n", __FUNCTION__); return stv0299_writereg (i2c, 0x31, 0x04); + } case FEC_5_6: + { + dprintk ("%s : FEC_5_6\n", __FUNCTION__); return stv0299_writereg (i2c, 0x31, 0x08); + } case FEC_7_8: + { + dprintk ("%s : FEC_7_8\n", __FUNCTION__); return stv0299_writereg (i2c, 0x31, 0x10); + } default: + { + dprintk ("%s : FEC invalid\n", __FUNCTION__); return -EINVAL; } + } } @@ -607,11 +692,20 @@ static int stv0299_set_tone (struct dvb_i2c_bus *i2c, fe_sec_tone_mode_t tone) switch (tone) { case SEC_TONE_ON: + { + dprintk("%s: TONE_ON\n", __FUNCTION__); return stv0299_writereg (i2c, 0x08, val | 0x3); + } case SEC_TONE_OFF: + { + dprintk("%s: TONE_OFF\n", __FUNCTION__); return stv0299_writereg (i2c, 0x08, (val & ~0x3) | 0x02); + } default: + { + dprintk("%s: TONE INVALID\n", __FUNCTION__); return -EINVAL; + } }; } @@ -654,8 +748,9 @@ static int stv0299_set_voltage (struct dvb_i2c_bus *i2c, fe_sec_voltage_t voltag static int stv0299_set_symbolrate (struct dvb_i2c_bus *i2c, u32 srate) { + u64 big = srate; u32 ratio; - u32 tmp; + u8 aclk = 0xb4, bclk = 0x51; if (srate > M_CLK) @@ -669,19 +764,23 @@ static int stv0299_set_symbolrate (struct dvb_i2c_bus *i2c, u32 srate) if (srate < 3000000) { aclk = 0xb7; bclk = 0x4b; } if (srate < 1500000) { aclk = 0xb7; bclk = 0x47; } -#define FIN (M_CLK >> 4) - - tmp = srate << 4; - ratio = tmp / FIN; - - tmp = (tmp % FIN) << 8; - ratio = (ratio << 8) + tmp / FIN; - - tmp = (tmp % FIN) << 8; - ratio = (ratio << 8) + tmp / FIN; - stv0299_writereg (i2c, 0x13, aclk); stv0299_writereg (i2c, 0x14, bclk); + + dprintk("%s : big = 0x%08x%08x\n", __FUNCTION__, (int) ((big>>32) & 0xffffffff), (int) (big & 0xffffffff) ); + + big = big << 20; + + dprintk("%s : big = 0x%08x%08x\n", __FUNCTION__, (int) ((big>>32) & 0xffffffff), (int) (big & 0xffffffff) ); + + do_div(big, M_CLK); + + dprintk("%s : big = 0x%08x%08x\n", __FUNCTION__, (int) ((big>>32) & 0xffffffff), (int) (big & 0xffffffff) ); + + ratio = big << 4; + + dprintk("%s : ratio = %i\n", __FUNCTION__, ratio); + stv0299_writereg (i2c, 0x1f, (ratio >> 16) & 0xff); stv0299_writereg (i2c, 0x20, (ratio >> 8) & 0xff); stv0299_writereg (i2c, 0x21, (ratio ) & 0xf0); @@ -711,6 +810,9 @@ static int stv0299_get_symbolrate (struct dvb_i2c_bus *i2c) offset = (s32) rtf * (srate / 4096L); offset /= 128; + dprintk ("%s : srate = %i\n", __FUNCTION__, srate); + dprintk ("%s : ofset = %i\n", __FUNCTION__, offset); + srate += offset; srate += 1000; @@ -726,6 +828,8 @@ static int uni0299_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg) int tuner_type = (long) fe->data; struct dvb_i2c_bus *i2c = fe->i2c; + dprintk ("%s\n", __FUNCTION__); + switch (cmd) { case FE_GET_INFO: memcpy (arg, &uni0299_info, sizeof(struct dvb_frontend_info)); @@ -737,7 +841,7 @@ static int uni0299_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg) u8 signal = 0xff - stv0299_readreg (i2c, 0x18); u8 sync = stv0299_readreg (i2c, 0x1b); - dprintk ("VSTATUS: 0x%02x\n", sync); + dprintk ("%s : FE_READ_STATUS : VSTATUS: 0x%02x\n", __FUNCTION__, sync); *status = 0; @@ -769,7 +873,7 @@ static int uni0299_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg) s32 signal = 0xffff - ((stv0299_readreg (i2c, 0x18) << 8) | stv0299_readreg (i2c, 0x19)); - dprintk ("AGC2I: 0x%02x%02x, signal=0x%04x\n", + dprintk ("%s : FE_READ_SIGNAL_STRENGTH : AGC2I: 0x%02x%02x, signal=0x%04x\n", __FUNCTION__, stv0299_readreg (i2c, 0x18), stv0299_readreg (i2c, 0x19), (int) signal); @@ -795,6 +899,8 @@ static int uni0299_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg) { struct dvb_frontend_parameters *p = arg; + dprintk ("%s : FE_SET_FRONTEND\n", __FUNCTION__); + pll_set_tv_freq (i2c, p->frequency, tuner_type, p->u.qpsk.symbol_rate); @@ -860,6 +966,8 @@ static int uni0299_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg) static long probe_tuner (struct dvb_i2c_bus *i2c) { + struct dvb_adapter * adapter = (struct dvb_adapter *) i2c->adapter; + /* read the status register of TSA5059 */ u8 rpt[] = { 0x05, 0xb5 }; u8 stat [] = { 0 }; @@ -876,6 +984,17 @@ static long probe_tuner (struct dvb_i2c_bus *i2c) stv0299_writereg (i2c, 0x02, 0x30); stv0299_writereg (i2c, 0x03, 0x00); + + printk ("%s: try to attach to %s\n", __FUNCTION__, adapter->name); + + if ( strcmp(adapter->name, "Technisat SkyStar2 driver") == 0 ) + { + printk ("%s: setup for tuner Samsung TBMU24112IMB\n", __FILE__); + + return SAMSUNG_TBMU24112IMB; + } + + if ((ret = i2c->xfer(i2c, msg1, 2)) == 2) { printk ("%s: setup for tuner SU1278/SH\n", __FILE__); return PHILIPS_SU1278SH; |