static int m88ds3103_set_frontend()

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;
}