in dvb-frontends/m88ds3103.c [618:1009]
static int m88ds3103_set_frontend(struct dvb_frontend *fe)
{
struct m88ds3103_dev *dev = fe->demodulator_priv;
struct i2c_client *client = dev->client;
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
int ret, len;
const struct m88ds3103_reg_val *init;
u8 u8tmp, u8tmp1 = 0, u8tmp2 = 0; /* silence compiler warning */
u8 buf[3];
u16 u16tmp;
u32 tuner_frequency_khz, target_mclk, u32tmp;
s32 s32tmp;
static const struct reg_sequence reset_buf[] = {
{0x07, 0x80}, {0x07, 0x00}
};
dev_dbg(&client->dev,
"delivery_system=%d modulation=%d frequency=%u symbol_rate=%d inversion=%d pilot=%d rolloff=%d\n",
c->delivery_system, c->modulation, c->frequency, c->symbol_rate,
c->inversion, c->pilot, c->rolloff);
if (!dev->warm) {
ret = -EAGAIN;
goto err;
}
/* reset */
ret = regmap_multi_reg_write(dev->regmap, reset_buf, 2);
if (ret)
goto err;
/* 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;
}
/* program tuner */
if (fe->ops.tuner_ops.set_params) {
ret = fe->ops.tuner_ops.set_params(fe);
if (ret)
goto err;
}
if (fe->ops.tuner_ops.get_frequency) {
ret = fe->ops.tuner_ops.get_frequency(fe, &tuner_frequency_khz);
if (ret)
goto err;
} else {
/*
* Use nominal target frequency as tuner driver does not provide
* actual frequency used. Carrier offset calculation is not
* valid.
*/
tuner_frequency_khz = c->frequency;
}
/* 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;
else
dev->mclk = 96000000;
if (c->delivery_system == SYS_DVBS)
target_mclk = 96000000;
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)
goto err;
usleep_range(10000, 20000);
} else {
/* set M88DS3103 mclk and ts mclk. */
dev->mclk = 96000000;
switch (dev->cfg->ts_mode) {
case M88DS3103_TS_SERIAL:
case M88DS3103_TS_SERIAL_D7:
target_mclk = dev->cfg->ts_clk;
break;
case M88DS3103_TS_PARALLEL:
case M88DS3103_TS_CI:
if (c->delivery_system == SYS_DVBS)
target_mclk = 96000000;
else {
if (c->symbol_rate < 18000000)
target_mclk = 96000000;
else if (c->symbol_rate < 28000000)
target_mclk = 144000000;
else
target_mclk = 192000000;
}
break;
default:
dev_dbg(&client->dev, "invalid ts_mode\n");
ret = -EINVAL;
goto err;
}
switch (target_mclk) {
case 96000000:
u8tmp1 = 0x02; /* 0b10 */
u8tmp2 = 0x01; /* 0b01 */
break;
case 144000000:
u8tmp1 = 0x00; /* 0b00 */
u8tmp2 = 0x01; /* 0b01 */
break;
case 192000000:
u8tmp1 = 0x03; /* 0b11 */
u8tmp2 = 0x00; /* 0b00 */
break;
}
ret = m88ds3103_update_bits(dev, 0x22, 0xc0, u8tmp1 << 6);
if (ret)
goto err;
ret = m88ds3103_update_bits(dev, 0x24, 0xc0, u8tmp2 << 6);
if (ret)
goto err;
}
ret = regmap_write(dev->regmap, 0xb2, 0x01);
if (ret)
goto err;
ret = regmap_write(dev->regmap, 0x00, 0x01);
if (ret)
goto err;
switch (c->delivery_system) {
case SYS_DVBS:
if (dev->chip_id == M88RS6000_CHIP_ID) {
len = ARRAY_SIZE(m88rs6000_dvbs_init_reg_vals);
init = m88rs6000_dvbs_init_reg_vals;
} else {
len = ARRAY_SIZE(m88ds3103_dvbs_init_reg_vals);
init = m88ds3103_dvbs_init_reg_vals;
}
break;
case SYS_DVBS2:
if (dev->chip_id == M88RS6000_CHIP_ID) {
len = ARRAY_SIZE(m88rs6000_dvbs2_init_reg_vals);
init = m88rs6000_dvbs2_init_reg_vals;
} else {
len = ARRAY_SIZE(m88ds3103_dvbs2_init_reg_vals);
init = m88ds3103_dvbs2_init_reg_vals;
}
break;
default:
dev_dbg(&client->dev, "invalid delivery_system\n");
ret = -EINVAL;
goto err;
}
/* program init table */
if (c->delivery_system != dev->delivery_system) {
ret = m88ds3103_wr_reg_val_tab(dev, init, len);
if (ret)
goto err;
}
if (dev->chip_id == M88RS6000_CHIP_ID) {
if (c->delivery_system == SYS_DVBS2 &&
c->symbol_rate <= 5000000) {
ret = regmap_write(dev->regmap, 0xc0, 0x04);
if (ret)
goto err;
buf[0] = 0x09;
buf[1] = 0x22;
buf[2] = 0x88;
ret = regmap_bulk_write(dev->regmap, 0x8a, buf, 3);
if (ret)
goto err;
}
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;
if (dev->chiptype != M88DS3103_CHIPTYPE_3103B) {
ret = m88ds3103_update_bits(dev, 0x30, 0x80, 0x80);
if (ret)
goto err;
}
}
switch (dev->cfg->ts_mode) {
case M88DS3103_TS_SERIAL:
u8tmp1 = 0x00;
u8tmp = 0x06;
break;
case M88DS3103_TS_SERIAL_D7:
u8tmp1 = 0x20;
u8tmp = 0x06;
break;
case M88DS3103_TS_PARALLEL:
u8tmp = 0x02;
if (dev->chiptype == M88DS3103_CHIPTYPE_3103B) {
u8tmp = 0x01;
u8tmp1 = 0x01;
}
break;
case M88DS3103_TS_CI:
u8tmp = 0x03;
break;
default:
dev_dbg(&client->dev, "invalid ts_mode\n");
ret = -EINVAL;
goto err;
}
if (dev->cfg->ts_clk_pol)
u8tmp |= 0x40;
/* TS mode */
ret = regmap_write(dev->regmap, 0xfd, u8tmp);
if (ret)
goto err;
switch (dev->cfg->ts_mode) {
case M88DS3103_TS_SERIAL:
case M88DS3103_TS_SERIAL_D7:
ret = m88ds3103_update_bits(dev, 0x29, 0x20, u8tmp1);
if (ret)
goto err;
u16tmp = 0;
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;
}
fallthrough;
default:
u16tmp = DIV_ROUND_UP(target_mclk, dev->cfg->ts_clk);
u8tmp1 = u16tmp / 2 - 1;
u8tmp2 = DIV_ROUND_UP(u16tmp, 2) - 1;
}
dev_dbg(&client->dev, "target_mclk=%u ts_clk=%u ts_clk_divide_ratio=%u\n",
target_mclk, dev->cfg->ts_clk, u16tmp);
/* u8tmp1[5:2] => fe[3:0], u8tmp1[1:0] => ea[7:6] */
/* u8tmp2[5:0] => ea[5:0] */
u8tmp = (u8tmp1 >> 2) & 0x0f;
ret = regmap_update_bits(dev->regmap, 0xfe, 0x0f, u8tmp);
if (ret)
goto err;
u8tmp = ((u8tmp1 & 0x03) << 6) | u8tmp2 >> 0;
ret = regmap_write(dev->regmap, 0xea, u8tmp);
if (ret)
goto err;
if (c->symbol_rate <= 3000000)
u8tmp = 0x20;
else if (c->symbol_rate <= 10000000)
u8tmp = 0x10;
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;
ret = regmap_write(dev->regmap, 0xc8, u8tmp);
if (ret)
goto err;
ret = regmap_write(dev->regmap, 0xc4, 0x08);
if (ret)
goto err;
ret = regmap_write(dev->regmap, 0xc7, 0x00);
if (ret)
goto err;
u16tmp = DIV_ROUND_CLOSEST_ULL((u64)c->symbol_rate * 0x10000, dev->mclk);
buf[0] = (u16tmp >> 0) & 0xff;
buf[1] = (u16tmp >> 8) & 0xff;
ret = regmap_bulk_write(dev->regmap, 0x61, buf, 2);
if (ret)
goto err;
ret = m88ds3103_update_bits(dev, 0x4d, 0x02, dev->cfg->spec_inv << 1);
if (ret)
goto err;
ret = m88ds3103_update_bits(dev, 0x30, 0x10, dev->cfg->agc_inv << 4);
if (ret)
goto err;
ret = regmap_write(dev->regmap, 0x33, dev->cfg->agc);
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);
if (ret)
goto err;
}
dev_dbg(&client->dev, "carrier offset=%d\n",
(tuner_frequency_khz - c->frequency));
/* Use 32-bit calc as there is no s64 version of DIV_ROUND_CLOSEST() */
s32tmp = 0x10000 * (tuner_frequency_khz - c->frequency);
s32tmp = DIV_ROUND_CLOSEST(s32tmp, dev->mclk / 1000);
buf[0] = (s32tmp >> 0) & 0xff;
buf[1] = (s32tmp >> 8) & 0xff;
ret = regmap_bulk_write(dev->regmap, 0x5e, buf, 2);
if (ret)
goto err;
ret = regmap_write(dev->regmap, 0x00, 0x00);
if (ret)
goto err;
ret = regmap_write(dev->regmap, 0xb2, 0x00);
if (ret)
goto err;
dev->delivery_system = c->delivery_system;
return 0;
err:
dev_dbg(&client->dev, "failed=%d\n", ret);
return ret;
}