summaryrefslogtreecommitdiffstats
path: root/drivers/media/video/cx88/cx88-dvb.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video/cx88/cx88-dvb.c')
-rw-r--r--drivers/media/video/cx88/cx88-dvb.c214
1 files changed, 214 insertions, 0 deletions
diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c
index b14296923250..94ab862f0219 100644
--- a/drivers/media/video/cx88/cx88-dvb.c
+++ b/drivers/media/video/cx88/cx88-dvb.c
@@ -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,32 @@ static int dvb_register(struct cx8802_dev *dev)
}
break;
}
+ case CX88_BOARD_SAMSUNG_SMT_7020:
+ dev->ts_gen_cntrl = 0x08;
+
+ 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);