Загрузка данных


static int fsl_xcvr_ai_write(struct fsl_xcvr *xcvr, u8 reg, u32 data, bool phy)
{
	struct device *dev = &xcvr->pdev->dev;
	u32 val, idx, tidx;
	int ret;

	idx  = BIT(phy ? 26 : 24);
	tidx = BIT(phy ? 27 : 25);

	regmap_write(xcvr->regmap, FSL_XCVR_PHY_AI_CTRL_CLR, 0xFF | FSL_XCVR_PHY_AI_CTRL_AI_RWB);
	regmap_write(xcvr->regmap, FSL_XCVR_PHY_AI_CTRL_SET, reg);
	regmap_write(xcvr->regmap, FSL_XCVR_PHY_AI_WDATA, data);
	regmap_write(xcvr->regmap, FSL_XCVR_PHY_AI_CTRL_TOG, idx);

	ret = regmap_read_poll_timeout(xcvr->regmap, FSL_XCVR_PHY_AI_CTRL, val,
				       (val & idx) == ((val & tidx) >> 1),
				       10, 10000);
	if (ret)
		dev_err(dev, "AI timeout: failed to set %s reg 0x%02x=0x%08x\n",
			phy ? "PHY" : "PLL", reg, data);
	return ret;
}

static int fsl_xcvr_ai_read(struct fsl_xcvr *xcvr, u8 reg, u32 *data, bool phy)
{
	struct device *dev = &xcvr->pdev->dev;
	u32 val, idx, tidx;
	int ret;

	idx  = BIT(phy ? 26 : 24);
	tidx = BIT(phy ? 27 : 25);

	regmap_write(xcvr->regmap, FSL_XCVR_PHY_AI_CTRL_CLR, 0xFF | FSL_XCVR_PHY_AI_CTRL_AI_RWB);
	regmap_write(xcvr->regmap, FSL_XCVR_PHY_AI_CTRL_SET, reg | FSL_XCVR_PHY_AI_CTRL_AI_RWB);
	regmap_write(xcvr->regmap, FSL_XCVR_PHY_AI_CTRL_TOG, idx);

	ret = regmap_read_poll_timeout(xcvr->regmap, FSL_XCVR_PHY_AI_CTRL, val,
				       (val & idx) == ((val & tidx) >> 1),
				       10, 10000);
	if (ret)
		dev_err(dev, "AI timeout: failed to read %s reg 0x%02x\n",
			phy ? "PHY" : "PLL", reg);

	regmap_read(xcvr->regmap, FSL_XCVR_PHY_AI_RDATA, data);

	return ret;
}

static int fsl_xcvr_phy_reg_read(void *context, unsigned int reg, unsigned int *val)
{
	struct fsl_xcvr *xcvr = context;

	return fsl_xcvr_ai_read(xcvr, reg, val, 1);
}

static int fsl_xcvr_phy_reg_write(void *context, unsigned int reg, unsigned int val)
{
	struct fsl_xcvr *xcvr = context;

	return fsl_xcvr_ai_write(xcvr, reg, val, 1);
}

static int fsl_xcvr_pll_reg_read(void *context, unsigned int reg, unsigned int *val)
{
	struct fsl_xcvr *xcvr = context;

	return fsl_xcvr_ai_read(xcvr, reg, val, 0);
}

static int fsl_xcvr_pll_reg_write(void *context, unsigned int reg, unsigned int val)
{
	struct fsl_xcvr *xcvr = context;

	return fsl_xcvr_ai_write(xcvr, reg, val, 0);
}

static int fsl_xcvr_en_phy_pll(struct fsl_xcvr *xcvr, u32 freq, bool tx)
{
	struct device *dev = &xcvr->pdev->dev;
	u32 i, div = 0, log2, val;
	int ret;

	if (!xcvr->soc_data->use_phy)
		return 0;

	for (i = 0; i < ARRAY_SIZE(fsl_xcvr_pll_cfg); i++) {
		if (fsl_xcvr_pll_cfg[i].fout % freq == 0) {
			div = fsl_xcvr_pll_cfg[i].fout / freq;
			break;
		}
	}

	if (!div || i >= ARRAY_SIZE(fsl_xcvr_pll_cfg))
		return -EINVAL;

	log2 = ilog2(div);

	/* Release AI interface from reset */
	ret = regmap_write(xcvr->regmap, FSL_XCVR_PHY_AI_CTRL_SET,
			   FSL_XCVR_PHY_AI_CTRL_AI_RESETN);
	if (ret < 0) {
		dev_err(dev, "Error while setting IER0: %d\n", ret);
		return ret;
	}

	switch (xcvr->soc_data->pll_ver) {
	case PLL_MX8MP:
		/* PLL: BANDGAP_SET: EN_VBG (enable bandgap) */
		regmap_set_bits(xcvr->regmap_pll, FSL_XCVR_PLL_BANDGAP,
				FSL_XCVR_PLL_BANDGAP_EN_VBG);

		/* PLL: CTRL0: DIV_INTEGER */
		regmap_write(xcvr->regmap_pll, FSL_XCVR_PLL_CTRL0, fsl_xcvr_pll_cfg[i].mfi);
		/* PLL: NUMERATOR: MFN */
		regmap_write(xcvr->regmap_pll, FSL_XCVR_PLL_NUM, fsl_xcvr_pll_cfg[i].mfn);
		/* PLL: DENOMINATOR: MFD */
		regmap_write(xcvr->regmap_pll, FSL_XCVR_PLL_DEN, fsl_xcvr_pll_cfg[i].mfd);
		/* PLL: CTRL0_SET: HOLD_RING_OFF, POWER_UP */
		regmap_set_bits(xcvr->regmap_pll, FSL_XCVR_PLL_CTRL0,
				FSL_XCVR_PLL_CTRL0_HROFF | FSL_XCVR_PLL_CTRL0_PWP);
		udelay(25);
		/* PLL: CTRL0: Clear Hold Ring Off */
		regmap_clear_bits(xcvr->regmap_pll, FSL_XCVR_PLL_CTRL0,
				  FSL_XCVR_PLL_CTRL0_HROFF);
		udelay(100);
		if (tx) { /* TX is enabled for SPDIF only */
			/* PLL: POSTDIV: PDIV0 */
			regmap_write(xcvr->regmap_pll, FSL_XCVR_PLL_PDIV,
				     FSL_XCVR_PLL_PDIVx(log2, 0));
			/* PLL: CTRL_SET: CLKMUX0_EN */
			regmap_set_bits(xcvr->regmap_pll, FSL_XCVR_PLL_CTRL0,
					FSL_XCVR_PLL_CTRL0_CM0_EN);
		} else if (xcvr->mode == FSL_XCVR_MODE_EARC) { /* eARC RX */
			/* PLL: POSTDIV: PDIV1 */
			regmap_write(xcvr->regmap_pll, FSL_XCVR_PLL_PDIV,
				     FSL_XCVR_PLL_PDIVx(log2, 1));
			/* PLL: CTRL_SET: CLKMUX1_EN */
			regmap_set_bits(xcvr->regmap_pll, FSL_XCVR_PLL_CTRL0,
					FSL_XCVR_PLL_CTRL0_CM1_EN);
		} else { /* SPDIF / ARC RX */
			/* PLL: POSTDIV: PDIV2 */
			regmap_write(xcvr->regmap_pll, FSL_XCVR_PLL_PDIV,
				     FSL_XCVR_PLL_PDIVx(log2, 2));
			/* PLL: CTRL_SET: CLKMUX2_EN */
			regmap_set_bits(xcvr->regmap_pll, FSL_XCVR_PLL_CTRL0,
					FSL_XCVR_PLL_CTRL0_CM2_EN);
		}
		break;
	case PLL_MX95:
		val = fsl_xcvr_pll_cfg[i].mfi << FSL_XCVR_GP_PLL_DIV_MFI_SHIFT | div;
		regmap_write(xcvr->regmap_pll, FSL_XCVR_GP_PLL_DIV, val);
		val = fsl_xcvr_pll_cfg[i].mfn << FSL_XCVR_GP_PLL_NUMERATOR_MFN_SHIFT;
		regmap_write(xcvr->regmap_pll, FSL_XCVR_GP_PLL_NUMERATOR, val);
		regmap_write(xcvr->regmap_pll, FSL_XCVR_GP_PLL_DENOMINATOR,
			     fsl_xcvr_pll_cfg[i].mfd);
		val = FSL_XCVR_GP_PLL_CTRL_POWERUP | FSL_XCVR_GP_PLL_CTRL_CLKMUX_EN;
		regmap_write(xcvr->regmap_pll, FSL_XCVR_GP_PLL_CTRL, val);
		break;
	default:
		dev_err(dev, "Error for PLL version %d\n", xcvr->soc_data->pll_ver);
		return -EINVAL;
	}

	if (xcvr->mode == FSL_XCVR_MODE_EARC) { /* eARC mode */
		/* PHY: CTRL_SET: TX_DIFF_OE, PHY_EN */
		regmap_set_bits(xcvr->regmap_phy, FSL_XCVR_PHY_CTRL,
				FSL_XCVR_PHY_CTRL_TSDIFF_OE |
				FSL_XCVR_PHY_CTRL_PHY_EN);
		/* PHY: CTRL2_SET: EARC_TX_MODE */
		regmap_set_bits(xcvr->regmap_phy, FSL_XCVR_PHY_CTRL2,
				FSL_XCVR_PHY_CTRL2_EARC_TXMS);
	} else if (!tx) { /* SPDIF / ARC RX mode */
		if (xcvr->mode == FSL_XCVR_MODE_SPDIF)
			/* PHY: CTRL_SET: SPDIF_EN */
			regmap_set_bits(xcvr->regmap_phy, FSL_XCVR_PHY_CTRL,
					FSL_XCVR_PHY_CTRL_SPDIF_EN);
		else	/* PHY: CTRL_SET: ARC RX setup */
			regmap_set_bits(xcvr->regmap_phy, FSL_XCVR_PHY_CTRL,
					FSL_XCVR_PHY_CTRL_PHY_EN |
					FSL_XCVR_PHY_CTRL_RX_CM_EN |
					fsl_xcvr_phy_arc_cfg[xcvr->arc_mode]);
	}

	dev_dbg(dev, "PLL Fexp: %u, Fout: %u, mfi: %u, mfn: %u, mfd: %d, div: %u, pdiv0: %u\n",
		freq, fsl_xcvr_pll_cfg[i].fout, fsl_xcvr_pll_cfg[i].mfi,
		fsl_xcvr_pll_cfg[i].mfn, fsl_xcvr_pll_cfg[i].mfd, div, log2);
	return 0;
}

static int fsl_xcvr_en_aud_pll(struct fsl_xcvr *xcvr, u32 freq)
{
	struct device *dev = &xcvr->pdev->dev;
	int ret;

	freq = xcvr->soc_data->spdif_only ? freq / 5 : freq;
	clk_disable_unprepare(xcvr->phy_clk);
	fsl_asoc_reparent_pll_clocks(dev, xcvr->phy_clk,
				     xcvr->pll8k_clk, xcvr->pll11k_clk, freq);
	ret = clk_set_rate(xcvr->phy_clk, freq);
	if (ret < 0) {
		dev_err(dev, "Error while setting AUD PLL rate: %d\n", ret);
		return ret;
	}
	ret = clk_prepare_enable(xcvr->phy_clk);
	if (ret) {
		dev_err(dev, "failed to start PHY clock: %d\n", ret);
		return ret;
	}

	if (!xcvr->soc_data->use_phy)
		return 0;
	/* Release AI interface from reset */
	ret = regmap_write(xcvr->regmap, FSL_XCVR_PHY_AI_CTRL_SET,
			   FSL_XCVR_PHY_AI_CTRL_AI_RESETN);
	if (ret < 0) {
		dev_err(dev, "Error while setting IER0: %d\n", ret);
		return ret;
	}

	if (xcvr->mode == FSL_XCVR_MODE_EARC) { /* eARC mode */
		/* PHY: CTRL_SET: TX_DIFF_OE, PHY_EN */
		regmap_set_bits(xcvr->regmap_phy, FSL_XCVR_PHY_CTRL,
				FSL_XCVR_PHY_CTRL_TSDIFF_OE |
				FSL_XCVR_PHY_CTRL_PHY_EN);
		/* PHY: CTRL2_SET: EARC_TX_MODE */
		regmap_set_bits(xcvr->regmap_phy, FSL_XCVR_PHY_CTRL2,
				FSL_XCVR_PHY_CTRL2_EARC_TXMS);
	} else { /* SPDIF mode */
		/* PHY: CTRL_SET: TX_CLK_AUD_SS | SPDIF_EN */
		regmap_set_bits(xcvr->regmap_phy, FSL_XCVR_PHY_CTRL,
				FSL_XCVR_PHY_CTRL_TX_CLK_AUD_SS |
				FSL_XCVR_PHY_CTRL_SPDIF_EN);
	}

	dev_dbg(dev, "PLL Fexp: %u\n", freq);

	return 0;
}

#define FSL_XCVR_SPDIF_RX_FREQ	175000000