|
|
|
@ -1,747 +0,0 @@
|
|
|
|
|
From: Brad Love <brad@nextdimension.cc>
|
|
|
|
|
https://git.linuxtv.org/brad/media_tree.git/log/?h=Montage-3103b.v2
|
|
|
|
|
support for m88ds3103b
|
|
|
|
|
|
|
|
|
|
diff --git a/drivers/media/dvb-frontends/m88ds3103.c b/drivers/media/dvb-frontends/m88ds3103.c
|
|
|
|
|
index c96f05f..a95461e 100644
|
|
|
|
|
--- a/drivers/media/dvb-frontends/m88ds3103.c
|
|
|
|
|
+++ b/drivers/media/dvb-frontends/m88ds3103.c
|
|
|
|
|
@@ -64,6 +64,92 @@ err:
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+/*
|
|
|
|
|
+ * m88ds3103b demod has an internal device related to clocking. First the i2c
|
|
|
|
|
+ * gate must be opened, for one transaction, then writes will be allowed.
|
|
|
|
|
+ */
|
|
|
|
|
+static int m88ds3103b_dt_write(struct m88ds3103_dev *dev, int reg, int data)
|
|
|
|
|
+{
|
|
|
|
|
+ struct i2c_client *client = dev->client;
|
|
|
|
|
+ u8 buf[] = {reg, data};
|
|
|
|
|
+ u8 val;
|
|
|
|
|
+ int ret;
|
|
|
|
|
+ struct i2c_msg msg = {
|
|
|
|
|
+ .addr = dev->dt_addr, .flags = 0, .buf = buf, .len = 2
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ m88ds3103_update_bits(dev, 0x11, 0x01, 0x00);
|
|
|
|
|
+
|
|
|
|
|
+ val = 0x11;
|
|
|
|
|
+ ret = regmap_write(dev->regmap, 0x03, val);
|
|
|
|
|
+ if (ret)
|
|
|
|
|
+ dev_dbg(&client->dev, "fail=%d\n", ret);
|
|
|
|
|
+
|
|
|
|
|
+ ret = i2c_transfer(dev->client->adapter, &msg, 1);
|
|
|
|
|
+ if (ret != 1) {
|
|
|
|
|
+ dev_dbg(&client->dev, "0x%02x (ret=%i, reg=0x%02x, value=0x%02x)\n",
|
|
|
|
|
+ dev->dt_addr, ret, reg, data);
|
|
|
|
|
+
|
|
|
|
|
+ m88ds3103_update_bits(dev, 0x11, 0x01, 0x01);
|
|
|
|
|
+ return -EREMOTEIO;
|
|
|
|
|
+ }
|
|
|
|
|
+ m88ds3103_update_bits(dev, 0x11, 0x01, 0x01);
|
|
|
|
|
+
|
|
|
|
|
+ dev_dbg(&client->dev, "0x%02x reg 0x%02x, value 0x%02x\n",
|
|
|
|
|
+ dev->dt_addr, reg, data);
|
|
|
|
|
+
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/*
|
|
|
|
|
+ * m88ds3103b demod has an internal device related to clocking. First the i2c
|
|
|
|
|
+ * gate must be opened, for two transactions, then reads will be allowed.
|
|
|
|
|
+ */
|
|
|
|
|
+static int m88ds3103b_dt_read(struct m88ds3103_dev *dev, u8 reg)
|
|
|
|
|
+{
|
|
|
|
|
+ struct i2c_client *client = dev->client;
|
|
|
|
|
+ int ret;
|
|
|
|
|
+ u8 val;
|
|
|
|
|
+ u8 b0[] = { reg };
|
|
|
|
|
+ u8 b1[] = { 0 };
|
|
|
|
|
+ struct i2c_msg msg[] = {
|
|
|
|
|
+ {
|
|
|
|
|
+ .addr = dev->dt_addr,
|
|
|
|
|
+ .flags = 0,
|
|
|
|
|
+ .buf = b0,
|
|
|
|
|
+ .len = 1
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ .addr = dev->dt_addr,
|
|
|
|
|
+ .flags = I2C_M_RD,
|
|
|
|
|
+ .buf = b1,
|
|
|
|
|
+ .len = 1
|
|
|
|
|
+ }
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ m88ds3103_update_bits(dev, 0x11, 0x01, 0x00);
|
|
|
|
|
+
|
|
|
|
|
+ val = 0x12;
|
|
|
|
|
+ ret = regmap_write(dev->regmap, 0x03, val);
|
|
|
|
|
+ if (ret)
|
|
|
|
|
+ dev_dbg(&client->dev, "fail=%d\n", ret);
|
|
|
|
|
+
|
|
|
|
|
+ ret = i2c_transfer(dev->client->adapter, msg, 2);
|
|
|
|
|
+ if (ret != 2) {
|
|
|
|
|
+ dev_dbg(&client->dev, "0x%02x (err=%d, reg=0x%02x)\n",
|
|
|
|
|
+ dev->dt_addr, ret, reg);
|
|
|
|
|
+
|
|
|
|
|
+ m88ds3103_update_bits(dev, 0x11, 0x01, 0x01);
|
|
|
|
|
+ return -EREMOTEIO;
|
|
|
|
|
+ }
|
|
|
|
|
+ m88ds3103_update_bits(dev, 0x11, 0x01, 0x01);
|
|
|
|
|
+
|
|
|
|
|
+ dev_dbg(&client->dev, "0x%02x reg 0x%02x, value 0x%02x\n",
|
|
|
|
|
+ dev->dt_addr, reg, b1[0]);
|
|
|
|
|
+
|
|
|
|
|
+ return b1[0];
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
/*
|
|
|
|
|
* Get the demodulator AGC PWM voltage setting supplied to the tuner.
|
|
|
|
|
*/
|
|
|
|
|
@@ -288,6 +374,253 @@ err:
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+static int m88ds3103b_select_mclk(struct m88ds3103_dev *dev)
|
|
|
|
|
+{
|
|
|
|
|
+ struct i2c_client *client = dev->client;
|
|
|
|
|
+ struct dtv_frontend_properties *c = &dev->fe.dtv_property_cache;
|
|
|
|
|
+ u32 adc_Freq_MHz[3] = {96, 93, 99};
|
|
|
|
|
+ u8 reg16_list[3] = {96, 92, 100}, reg16, reg15;
|
|
|
|
|
+ u32 offset_MHz[3];
|
|
|
|
|
+ u32 max_offset = 0;
|
|
|
|
|
+ u32 old_setting = dev->mclk;
|
|
|
|
|
+ u32 tuner_freq_MHz = c->frequency / 1000;
|
|
|
|
|
+ u8 i;
|
|
|
|
|
+ char big_symbol = 0;
|
|
|
|
|
+
|
|
|
|
|
+ big_symbol = (c->symbol_rate > 45010000) ? 1 : 0;
|
|
|
|
|
+
|
|
|
|
|
+ if (big_symbol) {
|
|
|
|
|
+ reg16 = 115;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ reg16 = 96;
|
|
|
|
|
+
|
|
|
|
|
+ /* TODO: IS THIS NECESSARY ? */
|
|
|
|
|
+ for (i = 0; i < 3; i++) {
|
|
|
|
|
+ offset_MHz[i] = tuner_freq_MHz % adc_Freq_MHz[i];
|
|
|
|
|
+
|
|
|
|
|
+ if (offset_MHz[i] > (adc_Freq_MHz[i] / 2))
|
|
|
|
|
+ offset_MHz[i] = adc_Freq_MHz[i] - offset_MHz[i];
|
|
|
|
|
+
|
|
|
|
|
+ if (offset_MHz[i] > max_offset) {
|
|
|
|
|
+ max_offset = offset_MHz[i];
|
|
|
|
|
+ reg16 = reg16_list[i];
|
|
|
|
|
+ dev->mclk = adc_Freq_MHz[i] * 1000 * 1000;
|
|
|
|
|
+
|
|
|
|
|
+ if (big_symbol)
|
|
|
|
|
+ dev->mclk /= 2;
|
|
|
|
|
+
|
|
|
|
|
+ dev_dbg(&client->dev, "modifying mclk %u -> %u\n",
|
|
|
|
|
+ old_setting, dev->mclk);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (dev->mclk == 93000000)
|
|
|
|
|
+ regmap_write(dev->regmap, 0xA0, 0x42);
|
|
|
|
|
+ else if (dev->mclk == 96000000)
|
|
|
|
|
+ regmap_write(dev->regmap, 0xA0, 0x44);
|
|
|
|
|
+ else if (dev->mclk == 99000000)
|
|
|
|
|
+ regmap_write(dev->regmap, 0xA0, 0x46);
|
|
|
|
|
+ else if (dev->mclk == 110250000)
|
|
|
|
|
+ regmap_write(dev->regmap, 0xA0, 0x4E);
|
|
|
|
|
+ else
|
|
|
|
|
+ regmap_write(dev->regmap, 0xA0, 0x44);
|
|
|
|
|
+
|
|
|
|
|
+ reg15 = m88ds3103b_dt_read(dev, 0x15);
|
|
|
|
|
+
|
|
|
|
|
+ m88ds3103b_dt_write(dev, 0x05, 0x40);
|
|
|
|
|
+ m88ds3103b_dt_write(dev, 0x11, 0x08);
|
|
|
|
|
+
|
|
|
|
|
+ if (big_symbol)
|
|
|
|
|
+ reg15 |= 0x02;
|
|
|
|
|
+ else
|
|
|
|
|
+ reg15 &= ~0x02;
|
|
|
|
|
+
|
|
|
|
|
+ m88ds3103b_dt_write(dev, 0x15, reg15);
|
|
|
|
|
+ m88ds3103b_dt_write(dev, 0x16, reg16);
|
|
|
|
|
+
|
|
|
|
|
+ usleep_range(5000, 5500);
|
|
|
|
|
+
|
|
|
|
|
+ m88ds3103b_dt_write(dev, 0x05, 0x00);
|
|
|
|
|
+ m88ds3103b_dt_write(dev, 0x11, (u8)(big_symbol ? 0x0E : 0x0A));
|
|
|
|
|
+
|
|
|
|
|
+ usleep_range(5000, 5500);
|
|
|
|
|
+
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static int m88ds3103b_set_mclk(struct m88ds3103_dev *dev, u32 mclk_khz)
|
|
|
|
|
+{
|
|
|
|
|
+ u8 reg11 = 0x0A, reg15, reg16, reg1D, reg1E, reg1F, tmp;
|
|
|
|
|
+ u8 sm, f0 = 0, f1 = 0, f2 = 0, f3 = 0, pll_ldpc_mode;
|
|
|
|
|
+ u16 pll_div_fb, N;
|
|
|
|
|
+ u32 div;
|
|
|
|
|
+
|
|
|
|
|
+ reg15 = m88ds3103b_dt_read(dev, 0x15);
|
|
|
|
|
+ reg16 = m88ds3103b_dt_read(dev, 0x16);
|
|
|
|
|
+ reg1D = m88ds3103b_dt_read(dev, 0x1D);
|
|
|
|
|
+
|
|
|
|
|
+ if (dev->cfg->ts_mode != M88DS3103_TS_SERIAL) {
|
|
|
|
|
+ if (reg16 == 92)
|
|
|
|
|
+ tmp = 93;
|
|
|
|
|
+ else if (reg16 == 100)
|
|
|
|
|
+ tmp = 99;
|
|
|
|
|
+ else
|
|
|
|
|
+ tmp = 96;
|
|
|
|
|
+
|
|
|
|
|
+ mclk_khz *= tmp;
|
|
|
|
|
+ mclk_khz /= 96;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ pll_ldpc_mode = (reg15 >> 1) & 0x01;
|
|
|
|
|
+
|
|
|
|
|
+ pll_div_fb = (reg15 & 0x01) << 8;
|
|
|
|
|
+ pll_div_fb += reg16;
|
|
|
|
|
+ pll_div_fb += 32;
|
|
|
|
|
+
|
|
|
|
|
+ div = 9000 * pll_div_fb * 4;
|
|
|
|
|
+ div /= mclk_khz;
|
|
|
|
|
+
|
|
|
|
|
+ if (dev->cfg->ts_mode == M88DS3103_TS_SERIAL) {
|
|
|
|
|
+ reg11 |= 0x02;
|
|
|
|
|
+
|
|
|
|
|
+ if (div <= 32) {
|
|
|
|
|
+ N = 2;
|
|
|
|
|
+
|
|
|
|
|
+ f0 = 0;
|
|
|
|
|
+ f1 = div / N;
|
|
|
|
|
+ f2 = div - f1;
|
|
|
|
|
+ f3 = 0;
|
|
|
|
|
+ } else if (div <= 34) {
|
|
|
|
|
+ N = 3;
|
|
|
|
|
+
|
|
|
|
|
+ f0 = div / N;
|
|
|
|
|
+ f1 = (div - f0) / (N - 1);
|
|
|
|
|
+ f2 = div - f0 - f1;
|
|
|
|
|
+ f3 = 0;
|
|
|
|
|
+ } else if (div <= 64) {
|
|
|
|
|
+ N = 4;
|
|
|
|
|
+
|
|
|
|
|
+ f0 = div / N;
|
|
|
|
|
+ f1 = (div - f0) / (N - 1);
|
|
|
|
|
+ f2 = (div - f0 - f1) / (N - 2);
|
|
|
|
|
+ f3 = div - f0 - f1 - f2;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ N = 4;
|
|
|
|
|
+
|
|
|
|
|
+ f0 = 16;
|
|
|
|
|
+ f1 = 16;
|
|
|
|
|
+ f2 = 16;
|
|
|
|
|
+ f3 = 16;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (f0 == 16)
|
|
|
|
|
+ f0 = 0;
|
|
|
|
|
+ else if ((f0 < 8) && (f0 != 0))
|
|
|
|
|
+ f0 = 8;
|
|
|
|
|
+
|
|
|
|
|
+ if (f1 == 16)
|
|
|
|
|
+ f1 = 0;
|
|
|
|
|
+ else if ((f1 < 8) && (f1 != 0))
|
|
|
|
|
+ f1 = 8;
|
|
|
|
|
+
|
|
|
|
|
+ if (f2 == 16)
|
|
|
|
|
+ f2 = 0;
|
|
|
|
|
+ else if ((f2 < 8) && (f2 != 0))
|
|
|
|
|
+ f2 = 8;
|
|
|
|
|
+
|
|
|
|
|
+ if (f3 == 16)
|
|
|
|
|
+ f3 = 0;
|
|
|
|
|
+ else if ((f3 < 8) && (f3 != 0))
|
|
|
|
|
+ f3 = 8;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ reg11 &= ~0x02;
|
|
|
|
|
+
|
|
|
|
|
+ if (div <= 32) {
|
|
|
|
|
+ N = 2;
|
|
|
|
|
+
|
|
|
|
|
+ f0 = 0;
|
|
|
|
|
+ f1 = div / N;
|
|
|
|
|
+ f2 = div - f1;
|
|
|
|
|
+ f3 = 0;
|
|
|
|
|
+ } else if (div <= 48) {
|
|
|
|
|
+ N = 3;
|
|
|
|
|
+
|
|
|
|
|
+ f0 = div / N;
|
|
|
|
|
+ f1 = (div - f0) / (N - 1);
|
|
|
|
|
+ f2 = div - f0 - f1;
|
|
|
|
|
+ f3 = 0;
|
|
|
|
|
+ } else if (div <= 64) {
|
|
|
|
|
+ N = 4;
|
|
|
|
|
+
|
|
|
|
|
+ f0 = div / N;
|
|
|
|
|
+ f1 = (div - f0) / (N - 1);
|
|
|
|
|
+ f2 = (div - f0 - f1) / (N - 2);
|
|
|
|
|
+ f3 = div - f0 - f1 - f2;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ N = 4;
|
|
|
|
|
+
|
|
|
|
|
+ f0 = 16;
|
|
|
|
|
+ f1 = 16;
|
|
|
|
|
+ f2 = 16;
|
|
|
|
|
+ f3 = 16;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (f0 == 16)
|
|
|
|
|
+ f0 = 0;
|
|
|
|
|
+ else if ((f0 < 9) && (f0 != 0))
|
|
|
|
|
+ f0 = 9;
|
|
|
|
|
+
|
|
|
|
|
+ if (f1 == 16)
|
|
|
|
|
+ f1 = 0;
|
|
|
|
|
+ else if ((f1 < 9) && (f1 != 0))
|
|
|
|
|
+ f1 = 9;
|
|
|
|
|
+
|
|
|
|
|
+ if (f2 == 16)
|
|
|
|
|
+ f2 = 0;
|
|
|
|
|
+ else if ((f2 < 9) && (f2 != 0))
|
|
|
|
|
+ f2 = 9;
|
|
|
|
|
+
|
|
|
|
|
+ if (f3 == 16)
|
|
|
|
|
+ f3 = 0;
|
|
|
|
|
+ else if ((f3 < 9) && (f3 != 0))
|
|
|
|
|
+ f3 = 9;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ sm = N - 1;
|
|
|
|
|
+
|
|
|
|
|
+ /* Write to registers */
|
|
|
|
|
+ //reg15 &= 0x01;
|
|
|
|
|
+ //reg15 |= (pll_div_fb >> 8) & 0x01;
|
|
|
|
|
+
|
|
|
|
|
+ //reg16 = pll_div_fb & 0xFF;
|
|
|
|
|
+
|
|
|
|
|
+ reg1D &= ~0x03;
|
|
|
|
|
+ reg1D |= sm;
|
|
|
|
|
+ reg1D |= 0x80;
|
|
|
|
|
+
|
|
|
|
|
+ reg1E = ((f3 << 4) + f2) & 0xFF;
|
|
|
|
|
+ reg1F = ((f1 << 4) + f0) & 0xFF;
|
|
|
|
|
+
|
|
|
|
|
+ m88ds3103b_dt_write(dev, 0x05, 0x40);
|
|
|
|
|
+ m88ds3103b_dt_write(dev, 0x11, 0x08);
|
|
|
|
|
+ m88ds3103b_dt_write(dev, 0x1D, reg1D);
|
|
|
|
|
+ m88ds3103b_dt_write(dev, 0x1E, reg1E);
|
|
|
|
|
+ m88ds3103b_dt_write(dev, 0x1F, reg1F);
|
|
|
|
|
+
|
|
|
|
|
+ m88ds3103b_dt_write(dev, 0x17, 0xc1);
|
|
|
|
|
+ m88ds3103b_dt_write(dev, 0x17, 0x81);
|
|
|
|
|
+
|
|
|
|
|
+ usleep_range(5000, 5500);
|
|
|
|
|
+
|
|
|
|
|
+ m88ds3103b_dt_write(dev, 0x05, 0x00);
|
|
|
|
|
+ m88ds3103b_dt_write(dev, 0x11, 0x0A);
|
|
|
|
|
+
|
|
|
|
|
+ usleep_range(5000, 5500);
|
|
|
|
|
+
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
static int m88ds3103_set_frontend(struct dvb_frontend *fe)
|
|
|
|
|
{
|
|
|
|
|
struct m88ds3103_dev *dev = fe->demodulator_priv;
|
|
|
|
|
@@ -298,7 +631,7 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe)
|
|
|
|
|
u8 u8tmp, u8tmp1 = 0, u8tmp2 = 0; /* silence compiler warning */
|
|
|
|
|
u8 buf[3];
|
|
|
|
|
u16 u16tmp;
|
|
|
|
|
- u32 tuner_frequency_khz, target_mclk;
|
|
|
|
|
+ u32 tuner_frequency_khz, target_mclk, u32tmp;
|
|
|
|
|
s32 s32tmp;
|
|
|
|
|
static const struct reg_sequence reset_buf[] = {
|
|
|
|
|
{0x07, 0x80}, {0x07, 0x00}
|
|
|
|
|
@@ -321,6 +654,20 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe)
|
|
|
|
|
|
|
|
|
|
/* Disable demod clock path */
|
|
|
|
|
if (dev->chip_id == M88RS6000_CHIP_ID) {
|
|
|
|
|
+ if (dev->chiptype == M88DS3103_CHIPTYPE_3103B) {
|
|
|
|
|
+ ret = regmap_read(dev->regmap, 0xb2, &u32tmp);
|
|
|
|
|
+ if (ret)
|
|
|
|
|
+ goto err;
|
|
|
|
|
+ if (u32tmp == 0x01) {
|
|
|
|
|
+ ret = regmap_write(dev->regmap, 0x00, 0x00);
|
|
|
|
|
+ if (ret)
|
|
|
|
|
+ goto err;
|
|
|
|
|
+ ret = regmap_write(dev->regmap, 0xb2, 0x00);
|
|
|
|
|
+ if (ret)
|
|
|
|
|
+ goto err;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
ret = regmap_write(dev->regmap, 0x06, 0xe0);
|
|
|
|
|
if (ret)
|
|
|
|
|
goto err;
|
|
|
|
|
@@ -346,7 +693,7 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe)
|
|
|
|
|
tuner_frequency_khz = c->frequency;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- /* select M88RS6000 demod main mclk and ts mclk from tuner die. */
|
|
|
|
|
+ /* set M88RS6000/DS3103B demod main mclk and ts mclk from tuner die */
|
|
|
|
|
if (dev->chip_id == M88RS6000_CHIP_ID) {
|
|
|
|
|
if (c->symbol_rate > 45010000)
|
|
|
|
|
dev->mclk = 110250000;
|
|
|
|
|
@@ -358,6 +705,11 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe)
|
|
|
|
|
else
|
|
|
|
|
target_mclk = 144000000;
|
|
|
|
|
|
|
|
|
|
+ if (dev->chiptype == M88DS3103_CHIPTYPE_3103B) {
|
|
|
|
|
+ m88ds3103b_select_mclk(dev);
|
|
|
|
|
+ m88ds3103b_set_mclk(dev, target_mclk / 1000);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
/* Enable demod clock path */
|
|
|
|
|
ret = regmap_write(dev->regmap, 0x06, 0x00);
|
|
|
|
|
if (ret)
|
|
|
|
|
@@ -469,12 +821,42 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe)
|
|
|
|
|
ret = m88ds3103_update_bits(dev, 0x9d, 0x08, 0x08);
|
|
|
|
|
if (ret)
|
|
|
|
|
goto err;
|
|
|
|
|
+
|
|
|
|
|
+ if (dev->chiptype == M88DS3103_CHIPTYPE_3103B) {
|
|
|
|
|
+ buf[0] = m88ds3103b_dt_read(dev, 0x15);
|
|
|
|
|
+ buf[1] = m88ds3103b_dt_read(dev, 0x16);
|
|
|
|
|
+
|
|
|
|
|
+ if (c->symbol_rate > 45010000) {
|
|
|
|
|
+ buf[0] &= ~0x03;
|
|
|
|
|
+ buf[0] |= 0x02;
|
|
|
|
|
+ buf[0] |= ((147 - 32) >> 8) & 0x01;
|
|
|
|
|
+ buf[1] = (147 - 32) & 0xFF;
|
|
|
|
|
+
|
|
|
|
|
+ dev->mclk = 110250 * 1000;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ buf[0] &= ~0x03;
|
|
|
|
|
+ buf[0] |= ((128 - 32) >> 8) & 0x01;
|
|
|
|
|
+ buf[1] = (128 - 32) & 0xFF;
|
|
|
|
|
+
|
|
|
|
|
+ dev->mclk = 96000 * 1000;
|
|
|
|
|
+ }
|
|
|
|
|
+ m88ds3103b_dt_write(dev, 0x15, buf[0]);
|
|
|
|
|
+ m88ds3103b_dt_write(dev, 0x16, buf[1]);
|
|
|
|
|
+
|
|
|
|
|
+ regmap_read(dev->regmap, 0x30, &u32tmp);
|
|
|
|
|
+ u32tmp &= ~0x80;
|
|
|
|
|
+ regmap_write(dev->regmap, 0x30, u32tmp & 0xff);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
ret = regmap_write(dev->regmap, 0xf1, 0x01);
|
|
|
|
|
if (ret)
|
|
|
|
|
goto err;
|
|
|
|
|
- ret = m88ds3103_update_bits(dev, 0x30, 0x80, 0x80);
|
|
|
|
|
- if (ret)
|
|
|
|
|
- goto err;
|
|
|
|
|
+
|
|
|
|
|
+ if (dev->chiptype != M88DS3103_CHIPTYPE_3103B) {
|
|
|
|
|
+ ret = m88ds3103_update_bits(dev, 0x30, 0x80, 0x80);
|
|
|
|
|
+ if (ret)
|
|
|
|
|
+ goto err;
|
|
|
|
|
+ }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (dev->cfg->ts_mode) {
|
|
|
|
|
@@ -488,6 +870,10 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe)
|
|
|
|
|
break;
|
|
|
|
|
case M88DS3103_TS_PARALLEL:
|
|
|
|
|
u8tmp = 0x02;
|
|
|
|
|
+ if (dev->chiptype == M88DS3103_CHIPTYPE_3103B) {
|
|
|
|
|
+ u8tmp = 0x01;
|
|
|
|
|
+ u8tmp1 = 0x01;
|
|
|
|
|
+ }
|
|
|
|
|
break;
|
|
|
|
|
case M88DS3103_TS_CI:
|
|
|
|
|
u8tmp = 0x03;
|
|
|
|
|
@@ -516,6 +902,12 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe)
|
|
|
|
|
u8tmp1 = 0x3f;
|
|
|
|
|
u8tmp2 = 0x3f;
|
|
|
|
|
break;
|
|
|
|
|
+ case M88DS3103_TS_PARALLEL:
|
|
|
|
|
+ if (dev->chiptype == M88DS3103_CHIPTYPE_3103B) {
|
|
|
|
|
+ ret = m88ds3103_update_bits(dev, 0x29, 0x01, u8tmp1);
|
|
|
|
|
+ if (ret)
|
|
|
|
|
+ goto err;
|
|
|
|
|
+ }
|
|
|
|
|
default:
|
|
|
|
|
u16tmp = DIV_ROUND_UP(target_mclk, dev->cfg->ts_clk);
|
|
|
|
|
u8tmp1 = u16tmp / 2 - 1;
|
|
|
|
|
@@ -543,6 +935,9 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe)
|
|
|
|
|
else
|
|
|
|
|
u8tmp = 0x06;
|
|
|
|
|
|
|
|
|
|
+ if (dev->chiptype == M88DS3103_CHIPTYPE_3103B)
|
|
|
|
|
+ m88ds3103b_set_mclk(dev, target_mclk / 1000);
|
|
|
|
|
+
|
|
|
|
|
ret = regmap_write(dev->regmap, 0xc3, 0x08);
|
|
|
|
|
if (ret)
|
|
|
|
|
goto err;
|
|
|
|
|
@@ -578,6 +973,16 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe)
|
|
|
|
|
if (ret)
|
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
|
|
+ if (dev->chiptype == M88DS3103_CHIPTYPE_3103B) {
|
|
|
|
|
+ /* enable/disable 192M LDPC clock */
|
|
|
|
|
+ ret = m88ds3103_update_bits(dev, 0x29, 0x10,
|
|
|
|
|
+ (c->delivery_system == SYS_DVBS) ? 0x10 : 0x0);
|
|
|
|
|
+ if (ret)
|
|
|
|
|
+ goto err;
|
|
|
|
|
+
|
|
|
|
|
+ ret = m88ds3103_update_bits(dev, 0xc9, 0x08, 0x08);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
dev_dbg(&client->dev, "carrier offset=%d\n",
|
|
|
|
|
(tuner_frequency_khz - c->frequency));
|
|
|
|
|
|
|
|
|
|
@@ -654,10 +1059,13 @@ static int m88ds3103_init(struct dvb_frontend *fe)
|
|
|
|
|
dev_info(&client->dev, "found a '%s' in cold state\n",
|
|
|
|
|
m88ds3103_ops.info.name);
|
|
|
|
|
|
|
|
|
|
- if (dev->chip_id == M88RS6000_CHIP_ID)
|
|
|
|
|
+ if (dev->chiptype == M88DS3103_CHIPTYPE_3103B)
|
|
|
|
|
+ name = M88DS3103B_FIRMWARE;
|
|
|
|
|
+ else if (dev->chip_id == M88RS6000_CHIP_ID)
|
|
|
|
|
name = M88RS6000_FIRMWARE;
|
|
|
|
|
else
|
|
|
|
|
name = M88DS3103_FIRMWARE;
|
|
|
|
|
+
|
|
|
|
|
/* request the firmware, this will block and timeout */
|
|
|
|
|
ret = request_firmware(&firmware, name, &client->dev);
|
|
|
|
|
if (ret) {
|
|
|
|
|
@@ -704,6 +1112,12 @@ static int m88ds3103_init(struct dvb_frontend *fe)
|
|
|
|
|
dev_info(&client->dev, "firmware version: %X.%X\n",
|
|
|
|
|
(utmp >> 4) & 0xf, (utmp >> 0 & 0xf));
|
|
|
|
|
|
|
|
|
|
+ if (dev->chiptype == M88DS3103_CHIPTYPE_3103B) {
|
|
|
|
|
+ m88ds3103b_dt_write(dev, 0x21, 0x92);
|
|
|
|
|
+ m88ds3103b_dt_write(dev, 0x15, 0x6C);
|
|
|
|
|
+ m88ds3103b_dt_write(dev, 0x17, 0xC1);
|
|
|
|
|
+ m88ds3103b_dt_write(dev, 0x17, 0x81);
|
|
|
|
|
+ }
|
|
|
|
|
warm:
|
|
|
|
|
/* warm state */
|
|
|
|
|
dev->warm = true;
|
|
|
|
|
@@ -1393,6 +1807,8 @@ static int m88ds3103_probe(struct i2c_client *client,
|
|
|
|
|
goto err_kfree;
|
|
|
|
|
|
|
|
|
|
dev->chip_id = utmp >> 1;
|
|
|
|
|
+ dev->chiptype = (u8)id->driver_data;
|
|
|
|
|
+
|
|
|
|
|
dev_dbg(&client->dev, "chip_id=%02x\n", dev->chip_id);
|
|
|
|
|
|
|
|
|
|
switch (dev->chip_id) {
|
|
|
|
|
@@ -1470,6 +1886,19 @@ static int m88ds3103_probe(struct i2c_client *client,
|
|
|
|
|
/* setup callbacks */
|
|
|
|
|
pdata->get_dvb_frontend = m88ds3103_get_dvb_frontend;
|
|
|
|
|
pdata->get_i2c_adapter = m88ds3103_get_i2c_adapter;
|
|
|
|
|
+
|
|
|
|
|
+ if (dev->chiptype == M88DS3103_CHIPTYPE_3103B) {
|
|
|
|
|
+ /* enable i2c repeater for tuner */
|
|
|
|
|
+ m88ds3103_update_bits(dev, 0x11, 0x01, 0x01);
|
|
|
|
|
+
|
|
|
|
|
+ /* get frontend address */
|
|
|
|
|
+ ret = regmap_read(dev->regmap, 0x29, &utmp);
|
|
|
|
|
+ if (ret)
|
|
|
|
|
+ goto err_kfree;
|
|
|
|
|
+ dev->dt_addr = ((utmp & 0x80) == 0) ? 0x42 >> 1 : 0x40 >> 1;
|
|
|
|
|
+ dev_err(&client->dev, "dt addr is 0x%02x", dev->dt_addr);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
return 0;
|
|
|
|
|
err_kfree:
|
|
|
|
|
kfree(dev);
|
|
|
|
|
@@ -1491,7 +1920,9 @@ static int m88ds3103_remove(struct i2c_client *client)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const struct i2c_device_id m88ds3103_id_table[] = {
|
|
|
|
|
- {"m88ds3103", 0},
|
|
|
|
|
+ {"m88ds3103", M88DS3103_CHIPTYPE_3103},
|
|
|
|
|
+ {"m88rs6000", M88DS3103_CHIPTYPE_RS6000},
|
|
|
|
|
+ {"m88ds3103b", M88DS3103_CHIPTYPE_3103B},
|
|
|
|
|
{}
|
|
|
|
|
};
|
|
|
|
|
MODULE_DEVICE_TABLE(i2c, m88ds3103_id_table);
|
|
|
|
|
@@ -1513,3 +1944,4 @@ MODULE_DESCRIPTION("Montage Technology M88DS3103 DVB-S/S2 demodulator driver");
|
|
|
|
|
MODULE_LICENSE("GPL");
|
|
|
|
|
MODULE_FIRMWARE(M88DS3103_FIRMWARE);
|
|
|
|
|
MODULE_FIRMWARE(M88RS6000_FIRMWARE);
|
|
|
|
|
+MODULE_FIRMWARE(M88DS3103B_FIRMWARE);
|
|
|
|
|
diff --git a/drivers/media/dvb-frontends/m88ds3103_priv.h b/drivers/media/dvb-frontends/m88ds3103_priv.h
|
|
|
|
|
index c825032..d656ec2 100644
|
|
|
|
|
--- a/drivers/media/dvb-frontends/m88ds3103_priv.h
|
|
|
|
|
+++ b/drivers/media/dvb-frontends/m88ds3103_priv.h
|
|
|
|
|
@@ -16,11 +16,17 @@
|
|
|
|
|
#include <linux/regmap.h>
|
|
|
|
|
#include <linux/math64.h>
|
|
|
|
|
|
|
|
|
|
-#define M88DS3103_FIRMWARE "dvb-demod-m88ds3103.fw"
|
|
|
|
|
-#define M88RS6000_FIRMWARE "dvb-demod-m88rs6000.fw"
|
|
|
|
|
+#define M88DS3103B_FIRMWARE "dvb-demod-m88ds3103b.fw"
|
|
|
|
|
+#define M88DS3103_FIRMWARE "dvb-demod-m88ds3103.fw"
|
|
|
|
|
+#define M88RS6000_FIRMWARE "dvb-demod-m88rs6000.fw"
|
|
|
|
|
+
|
|
|
|
|
#define M88RS6000_CHIP_ID 0x74
|
|
|
|
|
#define M88DS3103_CHIP_ID 0x70
|
|
|
|
|
|
|
|
|
|
+#define M88DS3103_CHIPTYPE_3103 0
|
|
|
|
|
+#define M88DS3103_CHIPTYPE_RS6000 1
|
|
|
|
|
+#define M88DS3103_CHIPTYPE_3103B 2
|
|
|
|
|
+
|
|
|
|
|
struct m88ds3103_dev {
|
|
|
|
|
struct i2c_client *client;
|
|
|
|
|
struct regmap_config regmap_config;
|
|
|
|
|
@@ -35,10 +41,13 @@ struct m88ds3103_dev {
|
|
|
|
|
struct i2c_mux_core *muxc;
|
|
|
|
|
/* auto detect chip id to do different config */
|
|
|
|
|
u8 chip_id;
|
|
|
|
|
+ /* chip type to differentiate m88rs6000 from m88ds3103b */
|
|
|
|
|
+ u8 chiptype;
|
|
|
|
|
/* main mclk is calculated for M88RS6000 dynamically */
|
|
|
|
|
s32 mclk;
|
|
|
|
|
u64 post_bit_error;
|
|
|
|
|
u64 post_bit_count;
|
|
|
|
|
+ u8 dt_addr;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct m88ds3103_reg_val {
|
|
|
|
|
diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
|
|
|
|
|
index def9cdd..a8c321d 100644
|
|
|
|
|
--- a/drivers/media/usb/em28xx/em28xx-cards.c
|
|
|
|
|
+++ b/drivers/media/usb/em28xx/em28xx-cards.c
|
|
|
|
|
@@ -2397,6 +2397,20 @@ const struct em28xx_board em28xx_boards[] = {
|
|
|
|
|
.has_dvb = 1,
|
|
|
|
|
.ir_codes = RC_MAP_PINNACLE_PCTV_HD,
|
|
|
|
|
},
|
|
|
|
|
+ /*
|
|
|
|
|
+ * 2013:0259 PCTV DVB-S2 Stick (461e_v2)
|
|
|
|
|
+ * Empia EM28178, Montage M88DS3103b, Montage M88TS2022, Allegro A8293
|
|
|
|
|
+ */
|
|
|
|
|
+ [EM28178_BOARD_PCTV_461E_V2] = {
|
|
|
|
|
+ .def_i2c_bus = 1,
|
|
|
|
|
+ .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE |
|
|
|
|
|
+ EM28XX_I2C_FREQ_400_KHZ,
|
|
|
|
|
+ .name = "PCTV DVB-S2 Stick (461e v2)",
|
|
|
|
|
+ .tuner_type = TUNER_ABSENT,
|
|
|
|
|
+ .tuner_gpio = pctv_461e,
|
|
|
|
|
+ .has_dvb = 1,
|
|
|
|
|
+ .ir_codes = RC_MAP_PINNACLE_PCTV_HD,
|
|
|
|
|
+ },
|
|
|
|
|
/*
|
|
|
|
|
* 2013:025f PCTV tripleStick (292e).
|
|
|
|
|
* Empia EM28178, Silicon Labs Si2168, Silicon Labs Si2157
|
|
|
|
|
@@ -2696,6 +2710,10 @@ struct usb_device_id em28xx_id_table[] = {
|
|
|
|
|
.driver_info = EM2765_BOARD_SPEEDLINK_VAD_LAPLACE },
|
|
|
|
|
{ USB_DEVICE(0x2013, 0x0258),
|
|
|
|
|
.driver_info = EM28178_BOARD_PCTV_461E },
|
|
|
|
|
+ { USB_DEVICE(0x2013, 0x0461),
|
|
|
|
|
+ .driver_info = EM28178_BOARD_PCTV_461E_V2 },
|
|
|
|
|
+ { USB_DEVICE(0x2013, 0x0259),
|
|
|
|
|
+ .driver_info = EM28178_BOARD_PCTV_461E_V2 },
|
|
|
|
|
{ USB_DEVICE(0x2013, 0x025f),
|
|
|
|
|
.driver_info = EM28178_BOARD_PCTV_292E },
|
|
|
|
|
{ USB_DEVICE(0x2013, 0x0264), /* Hauppauge WinTV-soloHD 292e SE */
|
|
|
|
|
diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c
|
|
|
|
|
index 0ab6c49..cd7e40c 100644
|
|
|
|
|
--- a/drivers/media/usb/em28xx/em28xx-dvb.c
|
|
|
|
|
+++ b/drivers/media/usb/em28xx/em28xx-dvb.c
|
|
|
|
|
@@ -1219,6 +1219,65 @@ static int em28178_dvb_init_pctv_461e(struct em28xx *dev)
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+static int em28178_dvb_init_pctv_461e_v2(struct em28xx *dev)
|
|
|
|
|
+{
|
|
|
|
|
+ struct em28xx_dvb *dvb = dev->dvb;
|
|
|
|
|
+ struct i2c_adapter *i2c_adapter;
|
|
|
|
|
+ struct m88ds3103_platform_data m88ds3103_pdata = {};
|
|
|
|
|
+ struct ts2020_config ts2020_config = {};
|
|
|
|
|
+ struct a8293_platform_data a8293_pdata = {};
|
|
|
|
|
+
|
|
|
|
|
+ /* attach demod */
|
|
|
|
|
+ m88ds3103_pdata.clk = 27000000;
|
|
|
|
|
+ m88ds3103_pdata.i2c_wr_max = 33;
|
|
|
|
|
+ m88ds3103_pdata.ts_mode = M88DS3103_TS_PARALLEL;
|
|
|
|
|
+ m88ds3103_pdata.ts_clk = 16000;
|
|
|
|
|
+ m88ds3103_pdata.ts_clk_pol = 1;
|
|
|
|
|
+ m88ds3103_pdata.agc = 0x99;
|
|
|
|
|
+ m88ds3103_pdata.agc_inv = 1;
|
|
|
|
|
+ m88ds3103_pdata.spec_inv = 1;
|
|
|
|
|
+ dvb->i2c_client_demod = dvb_module_probe("m88ds3103", "m88ds3103b",
|
|
|
|
|
+ &dev->i2c_adap[dev->def_i2c_bus],
|
|
|
|
|
+ 0x6a, &m88ds3103_pdata);
|
|
|
|
|
+
|
|
|
|
|
+ if (!dvb->i2c_client_demod) {
|
|
|
|
|
+ pr_err("%s() FUCK\n", __func__);
|
|
|
|
|
+ return -ENODEV;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ dvb->fe[0] = m88ds3103_pdata.get_dvb_frontend(dvb->i2c_client_demod);
|
|
|
|
|
+ i2c_adapter = m88ds3103_pdata.get_i2c_adapter(dvb->i2c_client_demod);
|
|
|
|
|
+
|
|
|
|
|
+ /* attach tuner */
|
|
|
|
|
+ ts2020_config.fe = dvb->fe[0];
|
|
|
|
|
+ dvb->i2c_client_tuner = dvb_module_probe("ts2020", "ts2022",
|
|
|
|
|
+ i2c_adapter,
|
|
|
|
|
+ 0x60, &ts2020_config);
|
|
|
|
|
+ if (!dvb->i2c_client_tuner) {
|
|
|
|
|
+ pr_err("%s() FUCK2\n", __func__);
|
|
|
|
|
+ dvb_module_release(dvb->i2c_client_demod);
|
|
|
|
|
+ return -ENODEV;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /* delegate signal strength measurement to tuner */
|
|
|
|
|
+ dvb->fe[0]->ops.read_signal_strength =
|
|
|
|
|
+ dvb->fe[0]->ops.tuner_ops.get_rf_strength;
|
|
|
|
|
+
|
|
|
|
|
+ /* attach SEC */
|
|
|
|
|
+ a8293_pdata.dvb_frontend = dvb->fe[0];
|
|
|
|
|
+ dvb->i2c_client_sec = dvb_module_probe("a8293", NULL,
|
|
|
|
|
+ &dev->i2c_adap[dev->def_i2c_bus],
|
|
|
|
|
+ 0x08, &a8293_pdata);
|
|
|
|
|
+ if (!dvb->i2c_client_sec) {
|
|
|
|
|
+ pr_err("%s() FUCK3\n", __func__);
|
|
|
|
|
+ dvb_module_release(dvb->i2c_client_tuner);
|
|
|
|
|
+ dvb_module_release(dvb->i2c_client_demod);
|
|
|
|
|
+ return -ENODEV;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
static int em28178_dvb_init_pctv_292e(struct em28xx *dev)
|
|
|
|
|
{
|
|
|
|
|
struct em28xx_dvb *dvb = dev->dvb;
|
|
|
|
|
@@ -1860,6 +1919,11 @@ static int em28xx_dvb_init(struct em28xx *dev)
|
|
|
|
|
if (result)
|
|
|
|
|
goto out_free;
|
|
|
|
|
break;
|
|
|
|
|
+ case EM28178_BOARD_PCTV_461E_V2:
|
|
|
|
|
+ result = em28178_dvb_init_pctv_461e_v2(dev);
|
|
|
|
|
+ if (result)
|
|
|
|
|
+ goto out_free;
|
|
|
|
|
+ break;
|
|
|
|
|
case EM28178_BOARD_PCTV_292E:
|
|
|
|
|
result = em28178_dvb_init_pctv_292e(dev);
|
|
|
|
|
if (result)
|
|
|
|
|
diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h
|
|
|
|
|
index 4ecadd5..ec38598 100644
|
|
|
|
|
--- a/drivers/media/usb/em28xx/em28xx.h
|
|
|
|
|
+++ b/drivers/media/usb/em28xx/em28xx.h
|
|
|
|
|
@@ -150,6 +150,7 @@
|
|
|
|
|
#define EM2884_BOARD_TERRATEC_H6 101
|
|
|
|
|
#define EM2882_BOARD_ZOLID_HYBRID_TV_STICK 102
|
|
|
|
|
#define EM2861_BOARD_MAGIX_VIDEOWANDLER2 103
|
|
|
|
|
+#define EM28178_BOARD_PCTV_461E_V2 104
|
|
|
|
|
|
|
|
|
|
/* Limits minimum and default number of buffers */
|
|
|
|
|
#define EM28XX_MIN_BUF 4
|
|
|
|
|
--
|
|
|
|
|
2.17.1
|
|
|
|
|
|