diff options
| author | Chunfeng Yun <chunfeng.yun@mediatek.com> | 2021-08-17 17:19:41 +0800 | 
|---|---|---|
| committer | Vinod Koul <vkoul@kernel.org> | 2021-08-17 15:51:58 +0530 | 
| commit | 39099a4433586cdf30a7fc73aae4c77159b4a8c7 (patch) | |
| tree | 257ec8395549a3235e8d2b431c6cec44ad022ec3 | |
| parent | 3fd6611242b9f4e218175c11c8233ac4ab9402e6 (diff) | |
phy: phy-mtk-tphy: support type switch by pericfg
Add support type switch between USB3, PCIe, SATA and SGMII by
pericfg register, this is used to take the place of efuse or
jumper.
Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
Link: https://lore.kernel.org/r/1629191987-20774-3-git-send-email-chunfeng.yun@mediatek.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>
| -rw-r--r-- | drivers/phy/mediatek/phy-mtk-tphy.c | 84 | 
1 files changed, 82 insertions, 2 deletions
| diff --git a/drivers/phy/mediatek/phy-mtk-tphy.c b/drivers/phy/mediatek/phy-mtk-tphy.c index 3259210f08a1..a6502058a1a5 100644 --- a/drivers/phy/mediatek/phy-mtk-tphy.c +++ b/drivers/phy/mediatek/phy-mtk-tphy.c @@ -10,11 +10,13 @@  #include <linux/delay.h>  #include <linux/io.h>  #include <linux/iopoll.h> +#include <linux/mfd/syscon.h>  #include <linux/module.h>  #include <linux/of_address.h>  #include <linux/of_device.h>  #include <linux/phy/phy.h>  #include <linux/platform_device.h> +#include <linux/regmap.h>  /* version V1 sub-banks offset base address */  /* banks shared by multiple phys */ @@ -280,6 +282,14 @@  #define RG_CDR_BIRLTD0_GEN3_MSK		GENMASK(4, 0)  #define RG_CDR_BIRLTD0_GEN3_VAL(x)	(0x1f & (x)) +/* PHY switch between pcie/usb3/sgmii/sata */ +#define USB_PHY_SWITCH_CTRL	0x0 +#define RG_PHY_SW_TYPE		GENMASK(3, 0) +#define RG_PHY_SW_PCIE		0x0 +#define RG_PHY_SW_USB3		0x1 +#define RG_PHY_SW_SGMII		0x2 +#define RG_PHY_SW_SATA		0x3 +  #define TPHY_CLKS_CNT	2  enum mtk_phy_version { @@ -322,7 +332,10 @@ struct mtk_phy_instance {  	};  	struct clk_bulk_data clks[TPHY_CLKS_CNT];  	u32 index; -	u8 type; +	u32 type; +	struct regmap *type_sw; +	u32 type_sw_reg; +	u32 type_sw_index;  	int eye_src;  	int eye_vrt;  	int eye_term; @@ -969,6 +982,64 @@ static void u2_phy_props_set(struct mtk_tphy *tphy,  	}  } +/* type switch for usb3/pcie/sgmii/sata */ +static int phy_type_syscon_get(struct mtk_phy_instance *instance, +			       struct device_node *dn) +{ +	struct of_phandle_args args; +	int ret; + +	/* type switch function is optional */ +	if (!of_property_read_bool(dn, "mediatek,syscon-type")) +		return 0; + +	ret = of_parse_phandle_with_fixed_args(dn, "mediatek,syscon-type", +					       2, 0, &args); +	if (ret) +		return ret; + +	instance->type_sw_reg = args.args[0]; +	instance->type_sw_index = args.args[1] & 0x3; /* <=3 */ +	instance->type_sw = syscon_node_to_regmap(args.np); +	of_node_put(args.np); +	dev_info(&instance->phy->dev, "type_sw - reg %#x, index %d\n", +		 instance->type_sw_reg, instance->type_sw_index); + +	return PTR_ERR_OR_ZERO(instance->type_sw); +} + +static int phy_type_set(struct mtk_phy_instance *instance) +{ +	int type; +	u32 mask; + +	if (!instance->type_sw) +		return 0; + +	switch (instance->type) { +	case PHY_TYPE_USB3: +		type = RG_PHY_SW_USB3; +		break; +	case PHY_TYPE_PCIE: +		type = RG_PHY_SW_PCIE; +		break; +	case PHY_TYPE_SGMII: +		type = RG_PHY_SW_SGMII; +		break; +	case PHY_TYPE_SATA: +		type = RG_PHY_SW_SATA; +		break; +	case PHY_TYPE_USB2: +	default: +		return 0; +	} + +	mask = RG_PHY_SW_TYPE << (instance->type_sw_index * BITS_PER_BYTE); +	regmap_update_bits(instance->type_sw, instance->type_sw_reg, mask, type); + +	return 0; +} +  static int mtk_phy_init(struct phy *phy)  {  	struct mtk_phy_instance *instance = phy_get_drvdata(phy); @@ -993,6 +1064,9 @@ static int mtk_phy_init(struct phy *phy)  	case PHY_TYPE_SATA:  		sata_phy_instance_init(tphy, instance);  		break; +	case PHY_TYPE_SGMII: +		/* nothing to do, only used to set type */ +		break;  	default:  		dev_err(tphy->dev, "incompatible PHY type\n");  		clk_bulk_disable_unprepare(TPHY_CLKS_CNT, instance->clks); @@ -1081,7 +1155,8 @@ static struct phy *mtk_phy_xlate(struct device *dev,  	if (!(instance->type == PHY_TYPE_USB2 ||  	      instance->type == PHY_TYPE_USB3 ||  	      instance->type == PHY_TYPE_PCIE || -	      instance->type == PHY_TYPE_SATA)) { +	      instance->type == PHY_TYPE_SATA || +	      instance->type == PHY_TYPE_SGMII)) {  		dev_err(dev, "unsupported device type: %d\n", instance->type);  		return ERR_PTR(-EINVAL);  	} @@ -1100,6 +1175,7 @@ static struct phy *mtk_phy_xlate(struct device *dev,  	}  	phy_parse_property(tphy, instance); +	phy_type_set(instance);  	return instance->phy;  } @@ -1244,6 +1320,10 @@ static int mtk_tphy_probe(struct platform_device *pdev)  		retval = devm_clk_bulk_get_optional(&phy->dev, TPHY_CLKS_CNT, clks);  		if (retval)  			goto put_child; + +		retval = phy_type_syscon_get(instance, child_np); +		if (retval) +			goto put_child;  	}  	provider = devm_of_phy_provider_register(dev, mtk_phy_xlate); | 
