V4L/DVB (13818): Add Prof 7500 DVB-S2 USB card
authorIgor M. Liplianin <liplianin@me.by>
Mon, 14 Dec 2009 23:24:56 +0000 (20:24 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Fri, 26 Feb 2010 18:10:24 +0000 (15:10 -0300)
The card based on stv0903 demod, stb6100 tuner.

Signed-off-by: Igor M. Liplianin <liplianin@me.by>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
drivers/media/dvb/dvb-usb/dw2102.c
drivers/media/dvb/frontends/stv0900.h
drivers/media/dvb/frontends/stv0900_core.c
drivers/media/dvb/frontends/stv0900_priv.h
drivers/media/dvb/frontends/stv0900_reg.h
drivers/media/dvb/frontends/stv0900_sw.c

index 64132c0..83a3552 100644 (file)
@@ -1,6 +1,7 @@
 /* DVB USB framework compliant Linux driver for the
 *      DVBWorld DVB-S 2101, 2102, DVB-S2 2104, DVB-C 3101,
-*      TeVii S600, S630, S650 Cards
+*      TeVii S600, S630, S650,
+*      Prof 1100, 7500 Cards
 * Copyright (C) 2008,2009 Igor M. Liplianin (liplianin@me.by)
 *
 *      This program is free software; you can redistribute it and/or modify it
@@ -469,6 +470,7 @@ static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
                                                                int num)
 {
        struct dvb_usb_device *d = i2c_get_adapdata(adap);
+       struct usb_device *udev = d->udev;
        int ret = 0;
        int len, i, j;
 
@@ -488,8 +490,13 @@ static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
                }
                case (DW2102_VOLTAGE_CTRL): {
                        u8 obuf[2];
+
+                       obuf[0] = 1;
+                       obuf[1] = msg[j].buf[1];/* off-on */
+                       ret = dw210x_op_rw(d->udev, 0x8a, 0, 0,
+                                       obuf, 2, DW210X_WRITE_MSG);
                        obuf[0] = 3;
-                       obuf[1] = msg[j].buf[0];
+                       obuf[1] = msg[j].buf[0];/* 13v-18v */
                        ret = dw210x_op_rw(d->udev, 0x8a, 0, 0,
                                        obuf, 2, DW210X_WRITE_MSG);
                        break;
@@ -527,6 +534,17 @@ static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
                                        i += 16;
                                        len -= 16;
                                } while (len > 0);
+                       } else if ((udev->descriptor.idProduct == 0x7500)
+                                       && (j < (num - 1))) {
+                               /* write register addr before read */
+                               u8 obuf[msg[j].len + 2];
+                               obuf[0] = msg[j + 1].len;
+                               obuf[1] = (msg[j].addr << 1);
+                               memcpy(obuf + 2, msg[j].buf, msg[j].len);
+                               ret = dw210x_op_rw(d->udev, 0x92, 0, 0,
+                                               obuf, msg[j].len + 2,
+                                               DW210X_WRITE_MSG);
+                               break;
                        } else {
                                /* write registers */
                                u8 obuf[msg[j].len + 2];
@@ -651,18 +669,25 @@ static int s6x0_read_mac_address(struct dvb_usb_device *d, u8 mac[6])
 
 static int dw210x_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
 {
-       static u8 command_13v[1] = {0x00};
-       static u8 command_18v[1] = {0x01};
-       struct i2c_msg msg[] = {
-               {.addr = DW2102_VOLTAGE_CTRL, .flags = 0,
-                       .buf = command_13v, .len = 1},
+       static u8 command_13v[] = {0x00, 0x01};
+       static u8 command_18v[] = {0x01, 0x01};
+       static u8 command_off[] = {0x00, 0x00};
+       struct i2c_msg msg = {
+               .addr = DW2102_VOLTAGE_CTRL,
+               .flags = 0,
+               .buf = command_off,
+               .len = 2,
        };
 
        struct dvb_usb_adapter *udev_adap =
                (struct dvb_usb_adapter *)(fe->dvb->priv);
        if (voltage == SEC_VOLTAGE_18)
-               msg[0].buf = command_18v;
-       i2c_transfer(&udev_adap->dev->i2c_adap, msg, 1);
+               msg.buf = command_18v;
+       else if (voltage == SEC_VOLTAGE_13)
+               msg.buf = command_13v;
+
+       i2c_transfer(&udev_adap->dev->i2c_adap, &msg, 1);
+
        return 0;
 }
 
@@ -735,6 +760,18 @@ static struct stv6110_config dw2104_stv6110_config = {
        .clk_div = 1,
 };
 
+static struct stv0900_config prof_7500_stv0900_config = {
+       .demod_address = 0x6a,
+       .demod_mode = 0,
+       .xtal = 27000000,
+       .clkmode = 3,/* 0-CLKI, 2-XTALI, else AUTO */
+       .diseqc_mode = 2,/* 2/3 PWM */
+       .tun1_maddress = 0,/* 0x60 */
+       .tun1_adc = 0,/* 2 Vpp */
+       .path1_mode = 3,
+       .tun1_type = 3,
+};
+
 static int dw2104_frontend_attach(struct dvb_usb_adapter *d)
 {
        struct dvb_tuner_ops *tuner_ops = NULL;
@@ -882,6 +919,19 @@ static int s6x0_frontend_attach(struct dvb_usb_adapter *d)
        return -EIO;
 }
 
+static int prof_7500_frontend_attach(struct dvb_usb_adapter *d)
+{
+       d->fe = dvb_attach(stv0900_attach, &prof_7500_stv0900_config,
+                                       &d->dev->i2c_adap, 0);
+       if (d->fe == NULL)
+               return -EIO;
+       d->fe->ops.set_voltage = dw210x_set_voltage;
+
+       info("Attached STV0900+STB6100A!\n");
+
+       return 0;
+}
+
 static int dw2102_tuner_attach(struct dvb_usb_adapter *adap)
 {
        dvb_attach(dvb_pll_attach, adap->fe, 0x60,
@@ -1073,6 +1123,7 @@ static struct usb_device_id dw2102_table[] = {
        {USB_DEVICE(0x9022, USB_PID_TEVII_S630)},
        {USB_DEVICE(0x3011, USB_PID_PROF_1100)},
        {USB_DEVICE(0x9022, USB_PID_TEVII_S660)},
+       {USB_DEVICE(0x3034, 0x7500)},
        { }
 };
 
@@ -1387,9 +1438,30 @@ static struct dvb_usb_device_properties s6x0_properties = {
        }
 };
 
+struct dvb_usb_device_properties *p7500;
+static struct dvb_usb_device_description d7500 = {
+       "Prof 7500 USB DVB-S2",
+       {&dw2102_table[9], NULL},
+       {NULL},
+};
+
 static int dw2102_probe(struct usb_interface *intf,
                const struct usb_device_id *id)
 {
+
+       p7500 = kzalloc(sizeof(struct dvb_usb_device_properties), GFP_KERNEL);
+       if (!p7500)
+               return -ENOMEM;
+       /* copy default structure */
+       memcpy(p7500, &s6x0_properties,
+                       sizeof(struct dvb_usb_device_properties));
+       /* fill only different fields */
+       p7500->firmware = "dvb-usb-p7500.fw";
+       p7500->devices[0] = d7500;
+       p7500->rc_key_map = tbs_rc_keys;
+       p7500->rc_key_map_size = ARRAY_SIZE(tbs_rc_keys);
+       p7500->adapter->frontend_attach = prof_7500_frontend_attach;
+
        if (0 == dvb_usb_device_init(intf, &dw2102_properties,
                        THIS_MODULE, NULL, adapter_nr) ||
            0 == dvb_usb_device_init(intf, &dw2104_properties,
@@ -1397,6 +1469,8 @@ static int dw2102_probe(struct usb_interface *intf,
            0 == dvb_usb_device_init(intf, &dw3101_properties,
                        THIS_MODULE, NULL, adapter_nr) ||
            0 == dvb_usb_device_init(intf, &s6x0_properties,
+                       THIS_MODULE, NULL, adapter_nr) ||
+           0 == dvb_usb_device_init(intf, p7500,
                        THIS_MODULE, NULL, adapter_nr))
                return 0;
 
@@ -1431,6 +1505,6 @@ MODULE_AUTHOR("Igor M. Liplianin (c) liplianin@me.by");
 MODULE_DESCRIPTION("Driver for DVBWorld DVB-S 2101, 2102, DVB-S2 2104,"
                                " DVB-C 3101 USB2.0,"
                                " TeVii S600, S630, S650, S660 USB2.0,"
-                               " Prof 1100 USB2.0 devices");
+                               " Prof 1100, 7500 USB2.0 devices");
 MODULE_VERSION("0.1");
 MODULE_LICENSE("GPL");
index 29c3fa8..e3e35d1 100644 (file)
@@ -49,6 +49,8 @@ struct stv0900_config {
        u8 tun2_maddress;
        u8 tun1_adc;/* 1 for stv6110, 2 for stb6100 */
        u8 tun2_adc;
+       u8 tun1_type;/* for now 3 for stb6100 auto, else - software */
+       u8 tun2_type;
        /* Set device param to start dma */
        int (*set_ts_params)(struct dvb_frontend *fe, int is_punctured);
 };
index 8762c86..115dc01 100644 (file)
@@ -567,6 +567,46 @@ void stv0900_set_bandwidth(struct dvb_frontend *fe, u32 bandwidth)
        }
 }
 
+u32 stv0900_get_freq_auto(struct stv0900_internal *intp, int demod)
+{
+       u32 freq, round;
+       /*      Formulat :
+       Tuner_Frequency(MHz)    = Regs / 64
+       Tuner_granularity(MHz)  = Regs / 2048
+       real_Tuner_Frequency    = Tuner_Frequency(MHz) - Tuner_granularity(MHz)
+       */
+       freq = (stv0900_get_bits(intp, TUN_RFFREQ2) << 10) +
+               (stv0900_get_bits(intp, TUN_RFFREQ1) << 2) +
+               stv0900_get_bits(intp, TUN_RFFREQ0);
+
+       freq = (freq * 1000) / 64;
+
+       round = (stv0900_get_bits(intp, TUN_RFRESTE1) >> 2) +
+               stv0900_get_bits(intp, TUN_RFRESTE0);
+
+       round = (round * 1000) / 2048;
+
+       return freq + round;
+}
+
+void stv0900_set_tuner_auto(struct stv0900_internal *intp, u32 Frequency,
+                                               u32 Bandwidth, int demod)
+{
+       u32 tunerFrequency;
+       /* Formulat:
+       Tuner_frequency_reg= Frequency(MHz)*64
+       */
+       tunerFrequency = (Frequency * 64) / 1000;
+
+       stv0900_write_bits(intp, TUN_RFFREQ2, (tunerFrequency >> 10));
+       stv0900_write_bits(intp, TUN_RFFREQ1, (tunerFrequency >> 2) & 0xff);
+       stv0900_write_bits(intp, TUN_RFFREQ0, (tunerFrequency & 0x03));
+       /* Low Pass Filter = BW /2 (MHz)*/
+       stv0900_write_bits(intp, TUN_BW, Bandwidth / 2000000);
+       /* Tuner Write trig */
+       stv0900_write_reg(intp, TNRLD, 1);
+}
+
 static s32 stv0900_get_rf_level(struct stv0900_internal *intp,
                                const struct stv0900_table *lookup,
                                enum fe_stv0900_demod_num demod)
@@ -1329,7 +1369,6 @@ static enum fe_stv0900_error stv0900_init_internal(struct dvb_frontend *fe,
        enum fe_stv0900_error error = STV0900_NO_ERROR;
        enum fe_stv0900_error demodError = STV0900_NO_ERROR;
        struct stv0900_internal *intp = NULL;
-
        int selosci, i;
 
        struct stv0900_inode *temp_int = find_inode(state->i2c_adap,
@@ -1404,6 +1443,27 @@ static enum fe_stv0900_error stv0900_init_internal(struct dvb_frontend *fe,
                stv0900_write_bits(intp, F0900_P1_RST_HWARE, 0);
        }
 
+       intp->tuner_type[0] = p_init->tuner1_type;
+       intp->tuner_type[1] = p_init->tuner2_type;
+       /* tuner init */
+       switch (p_init->tuner1_type) {
+       case 3: /*FE_AUTO_STB6100:*/
+               stv0900_write_reg(intp, R0900_P1_TNRCFG, 0x3c);
+               stv0900_write_reg(intp, R0900_P1_TNRCFG2, 0x86);
+               stv0900_write_reg(intp, R0900_P1_TNRCFG3, 0x18);
+               stv0900_write_reg(intp, R0900_P1_TNRXTAL, 27); /* 27MHz */
+               stv0900_write_reg(intp, R0900_P1_TNRSTEPS, 0x05);
+               stv0900_write_reg(intp, R0900_P1_TNRGAIN, 0x17);
+               stv0900_write_reg(intp, R0900_P1_TNRADJ, 0x1f);
+               stv0900_write_reg(intp, R0900_P1_TNRCTL2, 0x0);
+               stv0900_write_bits(intp, F0900_P1_TUN_TYPE, 3);
+               break;
+       /* case FE_SW_TUNER: */
+       default:
+               stv0900_write_bits(intp, F0900_P1_TUN_TYPE, 6);
+               break;
+       }
+
        stv0900_write_bits(intp, F0900_P1_TUN_MADDRESS, p_init->tun1_maddress);
        switch (p_init->tuner1_adc) {
        case 1:
@@ -1413,6 +1473,27 @@ static enum fe_stv0900_error stv0900_init_internal(struct dvb_frontend *fe,
                break;
        }
 
+       stv0900_write_reg(intp, R0900_P1_TNRLD, 1); /* hw tuner */
+
+       /* tuner init */
+       switch (p_init->tuner2_type) {
+       case 3: /*FE_AUTO_STB6100:*/
+               stv0900_write_reg(intp, R0900_P2_TNRCFG, 0x3c);
+               stv0900_write_reg(intp, R0900_P2_TNRCFG2, 0x86);
+               stv0900_write_reg(intp, R0900_P2_TNRCFG3, 0x18);
+               stv0900_write_reg(intp, R0900_P2_TNRXTAL, 27); /* 27MHz */
+               stv0900_write_reg(intp, R0900_P2_TNRSTEPS, 0x05);
+               stv0900_write_reg(intp, R0900_P2_TNRGAIN, 0x17);
+               stv0900_write_reg(intp, R0900_P2_TNRADJ, 0x1f);
+               stv0900_write_reg(intp, R0900_P2_TNRCTL2, 0x0);
+               stv0900_write_bits(intp, F0900_P2_TUN_TYPE, 3);
+               break;
+       /* case FE_SW_TUNER: */
+       default:
+               stv0900_write_bits(intp, F0900_P2_TUN_TYPE, 6);
+               break;
+       }
+
        stv0900_write_bits(intp, F0900_P2_TUN_MADDRESS, p_init->tun2_maddress);
        switch (p_init->tuner2_adc) {
        case 1:
@@ -1422,6 +1503,8 @@ static enum fe_stv0900_error stv0900_init_internal(struct dvb_frontend *fe,
                break;
        }
 
+       stv0900_write_reg(intp, R0900_P2_TNRLD, 1); /* hw tuner */
+
        stv0900_write_bits(intp, F0900_P1_TUN_IQSWAP, p_init->tun1_iq_inv);
        stv0900_write_bits(intp, F0900_P2_TUN_IQSWAP, p_init->tun2_iq_inv);
        stv0900_set_mclk(intp, 135000000);
@@ -1824,10 +1907,12 @@ struct dvb_frontend *stv0900_attach(const struct stv0900_config *config,
                init_params.tun1_maddress       = config->tun1_maddress;
                init_params.tun1_iq_inv         = STV0900_IQ_NORMAL;
                init_params.tuner1_adc          = config->tun1_adc;
+               init_params.tuner1_type         = config->tun1_type;
                init_params.path2_ts_clock      = config->path2_mode;
                init_params.ts_config           = config->ts_config_regs;
                init_params.tun2_maddress       = config->tun2_maddress;
                init_params.tuner2_adc          = config->tun2_adc;
+               init_params.tuner2_type         = config->tun2_type;
                init_params.tun2_iq_inv         = STV0900_IQ_SWAPPED;
 
                err_stv0900 = stv0900_init_internal(&state->frontend,
index d8ba8a9..b62b0f0 100644 (file)
@@ -247,6 +247,7 @@ struct stv0900_init_params{
 
        u8      tun1_maddress;
        int     tuner1_adc;
+       int     tuner1_type;
 
        /* IQ from the tuner1 to the demod */
        enum stv0900_iq_inversion       tun1_iq_inv;
@@ -254,6 +255,7 @@ struct stv0900_init_params{
 
        u8      tun2_maddress;
        int     tuner2_adc;
+       int     tuner2_type;
 
        /* IQ from the tuner2 to the demod */
        enum stv0900_iq_inversion       tun2_iq_inv;
@@ -309,6 +311,8 @@ struct stv0900_internal{
        s32     bw[2];
        s32     symbol_rate[2];
        s32     srch_range[2];
+       /* for software/auto tuner */
+       int     tuner_type[2];
 
        /* algorithm for search Blind, Cold or Warm*/
        enum fe_stv0900_search_algo     srch_algo[2];
@@ -394,4 +398,11 @@ extern enum
 fe_stv0900_tracking_standard stv0900_get_standard(struct dvb_frontend *fe,
                                enum fe_stv0900_demod_num demod);
 
+extern u32
+stv0900_get_freq_auto(struct stv0900_internal *intp, int demod);
+
+extern void
+stv0900_set_tuner_auto(struct stv0900_internal *intp, u32 Frequency,
+                                               u32 Bandwidth, int demod);
+
 #endif
index 7b8edf1..731afe9 100644 (file)
@@ -3174,17 +3174,21 @@ extern s32 shiftx(s32 x, int demod, s32 shift);
 #define R0900_P1_TNRRF1 0xf4e9
 #define TNRRF1 REGx(R0900_P1_TNRRF1)
 #define F0900_P1_TUN_RFFREQ2 0xf4e900ff
+#define TUN_RFFREQ2 FLDx(F0900_P1_TUN_RFFREQ2)
 
 /*P1_TNRRF0*/
 #define R0900_P1_TNRRF0 0xf4ea
 #define TNRRF0 REGx(R0900_P1_TNRRF0)
 #define F0900_P1_TUN_RFFREQ1 0xf4ea00ff
+#define TUN_RFFREQ1 FLDx(F0900_P1_TUN_RFFREQ1)
 
 /*P1_TNRBW*/
 #define R0900_P1_TNRBW 0xf4eb
 #define TNRBW REGx(R0900_P1_TNRBW)
 #define F0900_P1_TUN_RFFREQ0 0xf4eb00c0
+#define TUN_RFFREQ0 FLDx(F0900_P1_TUN_RFFREQ0)
 #define F0900_P1_TUN_BW 0xf4eb003f
+#define TUN_BW FLDx(F0900_P1_TUN_BW)
 
 /*P1_TNRADJ*/
 #define R0900_P1_TNRADJ 0xf4ec
@@ -3234,11 +3238,13 @@ extern s32 shiftx(s32 x, int demod, s32 shift);
 #define F0900_P1_TUN_I2CLOCKED 0xf4f60010
 #define F0900_P1_TUN_PROGDONE 0xf4f6000c
 #define F0900_P1_TUN_RFRESTE1 0xf4f60003
+#define TUN_RFRESTE1 FLDx(F0900_P1_TUN_RFRESTE1)
 
 /*P1_TNRRESTE*/
 #define R0900_P1_TNRRESTE 0xf4f7
 #define TNRRESTE REGx(R0900_P1_TNRRESTE)
 #define F0900_P1_TUN_RFRESTE0 0xf4f700ff
+#define TUN_RFRESTE0 FLDx(F0900_P1_TUN_RFRESTE0)
 
 /*P1_SMAPCOEF7*/
 #define R0900_P1_SMAPCOEF7 0xf500
index b8da87f..5161c28 100644 (file)
@@ -606,7 +606,12 @@ static int stv0900_get_demod_cold_lock(struct dvb_frontend *fe,
                        tuner_freq -= (current_step * currier_step);
 
                if (intp->chip_id <= 0x20) {
-                       stv0900_set_tuner(fe, tuner_freq, intp->bw[d]);
+                       if (intp->tuner_type[d] == 3)
+                               stv0900_set_tuner_auto(intp, tuner_freq,
+                                               intp->bw[d], demod);
+                       else
+                               stv0900_set_tuner(fe, tuner_freq, intp->bw[d]);
+
                        stv0900_write_reg(intp, DMDISTATE, 0x1c);
                        stv0900_write_reg(intp, CFRINIT1, 0);
                        stv0900_write_reg(intp, CFRINIT0, 0);
@@ -976,8 +981,16 @@ static void stv0900_track_optimization(struct dvb_frontend *fe)
                                        intp->rolloff) + 10000000;
 
                if ((intp->chip_id >= 0x20) || (blind_tun_sw == 1)) {
-                       if (intp->srch_algo[demod] != STV0900_WARM_START)
-                               stv0900_set_bandwidth(fe, intp->bw[demod]);
+                       if (intp->srch_algo[demod] != STV0900_WARM_START) {
+                               if (intp->tuner_type[demod] == 3)
+                                       stv0900_set_tuner_auto(intp,
+                                                       intp->freq[demod],
+                                                       intp->bw[demod],
+                                                       demod);
+                               else
+                                       stv0900_set_bandwidth(fe,
+                                                       intp->bw[demod]);
+                       }
                }
 
                if ((intp->srch_algo[demod] == STV0900_BLIND_SEARCH) ||
@@ -1202,7 +1215,11 @@ fe_stv0900_signal_type stv0900_get_signal_params(struct dvb_frontend *fe)
        }
 
        result->standard = stv0900_get_standard(fe, d);
-       result->frequency = stv0900_get_tuner_freq(fe);
+       if (intp->tuner_type[demod] == 3)
+               result->frequency = stv0900_get_freq_auto(intp, d);
+       else
+               result->frequency = stv0900_get_tuner_freq(fe);
+
        offsetFreq = stv0900_get_carr_freq(intp, intp->mclk, d) / 1000;
        result->frequency += offsetFreq;
        result->symbol_rate = stv0900_get_symbol_rate(intp, intp->mclk, d);
@@ -1239,7 +1256,11 @@ fe_stv0900_signal_type stv0900_get_signal_params(struct dvb_frontend *fe)
        if ((intp->srch_algo[d] == STV0900_BLIND_SEARCH) ||
                                (intp->symbol_rate[d] < 10000000)) {
                offsetFreq = result->frequency - intp->freq[d];
-               intp->freq[d] = stv0900_get_tuner_freq(fe);
+               if (intp->tuner_type[demod] == 3)
+                       intp->freq[d] = stv0900_get_freq_auto(intp, d);
+               else
+                       intp->freq[d] = stv0900_get_tuner_freq(fe);
+
                if (ABS(offsetFreq) <= ((intp->srch_range[d] / 2000) + 500))
                        range = STV0900_RANGEOK;
                else if (ABS(offsetFreq) <=
@@ -1481,7 +1502,12 @@ static u32 stv0900_search_srate_coarse(struct dvb_frontend *fe)
                        else
                                tuner_freq -= (current_step * currier_step);
 
-                       stv0900_set_tuner(fe, tuner_freq, intp->bw[demod]);
+                       if (intp->tuner_type[demod] == 3)
+                               stv0900_set_tuner_auto(intp, tuner_freq,
+                                               intp->bw[demod], demod);
+                       else
+                               stv0900_set_tuner(fe, tuner_freq,
+                                               intp->bw[demod]);
                }
        }
 
@@ -1875,7 +1901,11 @@ enum fe_stv0900_signal_type stv0900_algo(struct dvb_frontend *fe)
 
        }
 
-       stv0900_set_tuner(fe, intp->freq[demod], intp->bw[demod]);
+       if (intp->tuner_type[demod] == 3)
+               stv0900_set_tuner_auto(intp, intp->freq[demod],
+                               intp->bw[demod], demod);
+       else
+               stv0900_set_tuner(fe, intp->freq[demod], intp->bw[demod]);
 
        agc1_power = MAKEWORD(stv0900_get_bits(intp, AGCIQ_VALUE1),
                                stv0900_get_bits(intp, AGCIQ_VALUE0));