|
@@ -674,6 +674,194 @@ static int cx8802_alloc_frontends(struct cx8802_dev *dev)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+
|
|
|
+static u8 samsung_smt_7020_inittab[] = {
|
|
|
+ 0x01, 0x15,
|
|
|
+ 0x02, 0x00,
|
|
|
+ 0x03, 0x00,
|
|
|
+ 0x04, 0x7D,
|
|
|
+ 0x05, 0x0F,
|
|
|
+ 0x06, 0x02,
|
|
|
+ 0x07, 0x00,
|
|
|
+ 0x08, 0x60,
|
|
|
+
|
|
|
+ 0x0A, 0xC2,
|
|
|
+ 0x0B, 0x00,
|
|
|
+ 0x0C, 0x01,
|
|
|
+ 0x0D, 0x81,
|
|
|
+ 0x0E, 0x44,
|
|
|
+ 0x0F, 0x09,
|
|
|
+ 0x10, 0x3C,
|
|
|
+ 0x11, 0x84,
|
|
|
+ 0x12, 0xDA,
|
|
|
+ 0x13, 0x99,
|
|
|
+ 0x14, 0x8D,
|
|
|
+ 0x15, 0xCE,
|
|
|
+ 0x16, 0xE8,
|
|
|
+ 0x17, 0x43,
|
|
|
+ 0x18, 0x1C,
|
|
|
+ 0x19, 0x1B,
|
|
|
+ 0x1A, 0x1D,
|
|
|
+
|
|
|
+ 0x1C, 0x12,
|
|
|
+ 0x1D, 0x00,
|
|
|
+ 0x1E, 0x00,
|
|
|
+ 0x1F, 0x00,
|
|
|
+ 0x20, 0x00,
|
|
|
+ 0x21, 0x00,
|
|
|
+ 0x22, 0x00,
|
|
|
+ 0x23, 0x00,
|
|
|
+
|
|
|
+ 0x28, 0x02,
|
|
|
+ 0x29, 0x28,
|
|
|
+ 0x2A, 0x14,
|
|
|
+ 0x2B, 0x0F,
|
|
|
+ 0x2C, 0x09,
|
|
|
+ 0x2D, 0x05,
|
|
|
+
|
|
|
+ 0x31, 0x1F,
|
|
|
+ 0x32, 0x19,
|
|
|
+ 0x33, 0xFC,
|
|
|
+ 0x34, 0x13,
|
|
|
+ 0xff, 0xff,
|
|
|
+};
|
|
|
+
|
|
|
+
|
|
|
+static int samsung_smt_7020_tuner_set_params(struct dvb_frontend *fe,
|
|
|
+ struct dvb_frontend_parameters *params)
|
|
|
+{
|
|
|
+ struct cx8802_dev *dev = fe->dvb->priv;
|
|
|
+ u8 buf[4];
|
|
|
+ u32 div;
|
|
|
+ struct i2c_msg msg = {
|
|
|
+ .addr = 0x61,
|
|
|
+ .flags = 0,
|
|
|
+ .buf = buf,
|
|
|
+ .len = sizeof(buf) };
|
|
|
+
|
|
|
+ div = params->frequency / 125;
|
|
|
+
|
|
|
+ buf[0] = (div >> 8) & 0x7f;
|
|
|
+ buf[1] = div & 0xff;
|
|
|
+ buf[2] = 0x84; /* 0xC4 */
|
|
|
+ buf[3] = 0x00;
|
|
|
+
|
|
|
+ if (params->frequency < 1500000)
|
|
|
+ buf[3] |= 0x10;
|
|
|
+
|
|
|
+ if (fe->ops.i2c_gate_ctrl)
|
|
|
+ fe->ops.i2c_gate_ctrl(fe, 1);
|
|
|
+
|
|
|
+ if (i2c_transfer(&dev->core->i2c_adap, &msg, 1) != 1)
|
|
|
+ return -EIO;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int samsung_smt_7020_set_tone(struct dvb_frontend *fe,
|
|
|
+ fe_sec_tone_mode_t tone)
|
|
|
+{
|
|
|
+ struct cx8802_dev *dev = fe->dvb->priv;
|
|
|
+ struct cx88_core *core = dev->core;
|
|
|
+
|
|
|
+ cx_set(MO_GP0_IO, 0x0800);
|
|
|
+
|
|
|
+ switch (tone) {
|
|
|
+ case SEC_TONE_ON:
|
|
|
+ cx_set(MO_GP0_IO, 0x08);
|
|
|
+ break;
|
|
|
+ case SEC_TONE_OFF:
|
|
|
+ cx_clear(MO_GP0_IO, 0x08);
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int samsung_smt_7020_set_voltage(struct dvb_frontend *fe,
|
|
|
+ fe_sec_voltage_t voltage)
|
|
|
+{
|
|
|
+ struct cx8802_dev *dev = fe->dvb->priv;
|
|
|
+ struct cx88_core *core = dev->core;
|
|
|
+
|
|
|
+ u8 data;
|
|
|
+ struct i2c_msg msg = {
|
|
|
+ .addr = 8,
|
|
|
+ .flags = 0,
|
|
|
+ .buf = &data,
|
|
|
+ .len = sizeof(data) };
|
|
|
+
|
|
|
+ cx_set(MO_GP0_IO, 0x8000);
|
|
|
+
|
|
|
+ switch (voltage) {
|
|
|
+ case SEC_VOLTAGE_OFF:
|
|
|
+ break;
|
|
|
+ case SEC_VOLTAGE_13:
|
|
|
+ data = ISL6421_EN1 | ISL6421_LLC1;
|
|
|
+ cx_clear(MO_GP0_IO, 0x80);
|
|
|
+ break;
|
|
|
+ case SEC_VOLTAGE_18:
|
|
|
+ data = ISL6421_EN1 | ISL6421_LLC1 | ISL6421_VSEL1;
|
|
|
+ cx_clear(MO_GP0_IO, 0x80);
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ return -EINVAL;
|
|
|
+ };
|
|
|
+
|
|
|
+ return (i2c_transfer(&dev->core->i2c_adap, &msg, 1) == 1) ? 0 : -EIO;
|
|
|
+}
|
|
|
+
|
|
|
+static int samsung_smt_7020_stv0299_set_symbol_rate(struct dvb_frontend *fe,
|
|
|
+ u32 srate, u32 ratio)
|
|
|
+{
|
|
|
+ u8 aclk = 0;
|
|
|
+ u8 bclk = 0;
|
|
|
+
|
|
|
+ if (srate < 1500000) {
|
|
|
+ aclk = 0xb7;
|
|
|
+ bclk = 0x47;
|
|
|
+ } else if (srate < 3000000) {
|
|
|
+ aclk = 0xb7;
|
|
|
+ bclk = 0x4b;
|
|
|
+ } else if (srate < 7000000) {
|
|
|
+ aclk = 0xb7;
|
|
|
+ bclk = 0x4f;
|
|
|
+ } else if (srate < 14000000) {
|
|
|
+ aclk = 0xb7;
|
|
|
+ bclk = 0x53;
|
|
|
+ } else if (srate < 30000000) {
|
|
|
+ aclk = 0xb6;
|
|
|
+ bclk = 0x53;
|
|
|
+ } else if (srate < 45000000) {
|
|
|
+ aclk = 0xb4;
|
|
|
+ bclk = 0x51;
|
|
|
+ }
|
|
|
+
|
|
|
+ stv0299_writereg(fe, 0x13, aclk);
|
|
|
+ stv0299_writereg(fe, 0x14, bclk);
|
|
|
+ stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff);
|
|
|
+ stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff);
|
|
|
+ stv0299_writereg(fe, 0x21, ratio & 0xf0);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+static struct stv0299_config samsung_stv0299_config = {
|
|
|
+ .demod_address = 0x68,
|
|
|
+ .inittab = samsung_smt_7020_inittab,
|
|
|
+ .mclk = 88000000UL,
|
|
|
+ .invert = 0,
|
|
|
+ .skip_reinit = 0,
|
|
|
+ .lock_output = STV0299_LOCKOUTPUT_LK,
|
|
|
+ .volt13_op0_op1 = STV0299_VOLT13_OP1,
|
|
|
+ .min_delay_ms = 100,
|
|
|
+ .set_symbol_rate = samsung_smt_7020_stv0299_set_symbol_rate,
|
|
|
+};
|
|
|
+
|
|
|
static int dvb_register(struct cx8802_dev *dev)
|
|
|
{
|
|
|
struct cx88_core *core = dev->core;
|
|
@@ -1203,6 +1391,34 @@ static int dvb_register(struct cx8802_dev *dev)
|
|
|
}
|
|
|
break;
|
|
|
}
|
|
|
+ case CX88_BOARD_SAMSUNG_SMT_7020:
|
|
|
+ dev->ts_gen_cntrl = 0x08;
|
|
|
+
|
|
|
+ struct cx88_core *core = dev->core;
|
|
|
+
|
|
|
+ cx_set(MO_GP0_IO, 0x0101);
|
|
|
+
|
|
|
+ cx_clear(MO_GP0_IO, 0x01);
|
|
|
+ mdelay(100);
|
|
|
+ cx_set(MO_GP0_IO, 0x01);
|
|
|
+ mdelay(200);
|
|
|
+
|
|
|
+ fe0->dvb.frontend = dvb_attach(stv0299_attach,
|
|
|
+ &samsung_stv0299_config,
|
|
|
+ &dev->core->i2c_adap);
|
|
|
+ if (fe0->dvb.frontend) {
|
|
|
+ fe0->dvb.frontend->ops.tuner_ops.set_params =
|
|
|
+ samsung_smt_7020_tuner_set_params;
|
|
|
+ fe0->dvb.frontend->tuner_priv =
|
|
|
+ &dev->core->i2c_adap;
|
|
|
+ fe0->dvb.frontend->ops.set_voltage =
|
|
|
+ samsung_smt_7020_set_voltage;
|
|
|
+ fe0->dvb.frontend->ops.set_tone =
|
|
|
+ samsung_smt_7020_set_tone;
|
|
|
+ }
|
|
|
+
|
|
|
+ break;
|
|
|
+
|
|
|
default:
|
|
|
printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card isn't supported yet\n",
|
|
|
core->name);
|