xref: /OK3568_Linux_fs/kernel/drivers/phy/amlogic/phy-meson-axg-mipi-pcie-analog.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Amlogic AXG MIPI + PCIE analog PHY driver
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (C) 2019 Remi Pommarel <repk@triplefau.lt>
6*4882a593Smuzhiyun  */
7*4882a593Smuzhiyun #include <linux/module.h>
8*4882a593Smuzhiyun #include <linux/phy/phy.h>
9*4882a593Smuzhiyun #include <linux/regmap.h>
10*4882a593Smuzhiyun #include <linux/platform_device.h>
11*4882a593Smuzhiyun #include <dt-bindings/phy/phy.h>
12*4882a593Smuzhiyun 
13*4882a593Smuzhiyun #define HHI_MIPI_CNTL0 0x00
14*4882a593Smuzhiyun #define		HHI_MIPI_CNTL0_COMMON_BLOCK	GENMASK(31, 28)
15*4882a593Smuzhiyun #define		HHI_MIPI_CNTL0_ENABLE		BIT(29)
16*4882a593Smuzhiyun #define		HHI_MIPI_CNTL0_BANDGAP		BIT(26)
17*4882a593Smuzhiyun #define		HHI_MIPI_CNTL0_DECODE_TO_RTERM	GENMASK(15, 12)
18*4882a593Smuzhiyun #define		HHI_MIPI_CNTL0_OUTPUT_EN	BIT(3)
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun #define HHI_MIPI_CNTL1 0x01
21*4882a593Smuzhiyun #define		HHI_MIPI_CNTL1_CH0_CML_PDR_EN	BIT(12)
22*4882a593Smuzhiyun #define		HHI_MIPI_CNTL1_LP_ABILITY	GENMASK(5, 4)
23*4882a593Smuzhiyun #define		HHI_MIPI_CNTL1_LP_RESISTER	BIT(3)
24*4882a593Smuzhiyun #define		HHI_MIPI_CNTL1_INPUT_SETTING	BIT(2)
25*4882a593Smuzhiyun #define		HHI_MIPI_CNTL1_INPUT_SEL	BIT(1)
26*4882a593Smuzhiyun #define		HHI_MIPI_CNTL1_PRBS7_EN		BIT(0)
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun #define HHI_MIPI_CNTL2 0x02
29*4882a593Smuzhiyun #define		HHI_MIPI_CNTL2_CH_PU		GENMASK(31, 25)
30*4882a593Smuzhiyun #define		HHI_MIPI_CNTL2_CH_CTL		GENMASK(24, 19)
31*4882a593Smuzhiyun #define		HHI_MIPI_CNTL2_CH0_DIGDR_EN	BIT(18)
32*4882a593Smuzhiyun #define		HHI_MIPI_CNTL2_CH_DIGDR_EN	BIT(17)
33*4882a593Smuzhiyun #define		HHI_MIPI_CNTL2_LPULPS_EN	BIT(16)
34*4882a593Smuzhiyun #define		HHI_MIPI_CNTL2_CH_EN(n)		BIT(15 - (n))
35*4882a593Smuzhiyun #define		HHI_MIPI_CNTL2_CH0_LP_CTL	GENMASK(10, 1)
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun struct phy_axg_mipi_pcie_analog_priv {
38*4882a593Smuzhiyun 	struct phy *phy;
39*4882a593Smuzhiyun 	unsigned int mode;
40*4882a593Smuzhiyun 	struct regmap *regmap;
41*4882a593Smuzhiyun };
42*4882a593Smuzhiyun 
43*4882a593Smuzhiyun static const struct regmap_config phy_axg_mipi_pcie_analog_regmap_conf = {
44*4882a593Smuzhiyun 	.reg_bits = 8,
45*4882a593Smuzhiyun 	.val_bits = 32,
46*4882a593Smuzhiyun 	.reg_stride = 4,
47*4882a593Smuzhiyun 	.max_register = HHI_MIPI_CNTL2,
48*4882a593Smuzhiyun };
49*4882a593Smuzhiyun 
phy_axg_mipi_pcie_analog_power_on(struct phy * phy)50*4882a593Smuzhiyun static int phy_axg_mipi_pcie_analog_power_on(struct phy *phy)
51*4882a593Smuzhiyun {
52*4882a593Smuzhiyun 	struct phy_axg_mipi_pcie_analog_priv *priv = phy_get_drvdata(phy);
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun 	/* MIPI not supported yet */
55*4882a593Smuzhiyun 	if (priv->mode != PHY_TYPE_PCIE)
56*4882a593Smuzhiyun 		return -EINVAL;
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun 	regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0,
59*4882a593Smuzhiyun 			   HHI_MIPI_CNTL0_BANDGAP, HHI_MIPI_CNTL0_BANDGAP);
60*4882a593Smuzhiyun 
61*4882a593Smuzhiyun 	regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0,
62*4882a593Smuzhiyun 			   HHI_MIPI_CNTL0_ENABLE, HHI_MIPI_CNTL0_ENABLE);
63*4882a593Smuzhiyun 	return 0;
64*4882a593Smuzhiyun }
65*4882a593Smuzhiyun 
phy_axg_mipi_pcie_analog_power_off(struct phy * phy)66*4882a593Smuzhiyun static int phy_axg_mipi_pcie_analog_power_off(struct phy *phy)
67*4882a593Smuzhiyun {
68*4882a593Smuzhiyun 	struct phy_axg_mipi_pcie_analog_priv *priv = phy_get_drvdata(phy);
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun 	/* MIPI not supported yet */
71*4882a593Smuzhiyun 	if (priv->mode != PHY_TYPE_PCIE)
72*4882a593Smuzhiyun 		return -EINVAL;
73*4882a593Smuzhiyun 
74*4882a593Smuzhiyun 	regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0,
75*4882a593Smuzhiyun 			   HHI_MIPI_CNTL0_BANDGAP, 0);
76*4882a593Smuzhiyun 	regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0,
77*4882a593Smuzhiyun 			   HHI_MIPI_CNTL0_ENABLE, 0);
78*4882a593Smuzhiyun 	return 0;
79*4882a593Smuzhiyun }
80*4882a593Smuzhiyun 
phy_axg_mipi_pcie_analog_init(struct phy * phy)81*4882a593Smuzhiyun static int phy_axg_mipi_pcie_analog_init(struct phy *phy)
82*4882a593Smuzhiyun {
83*4882a593Smuzhiyun 	return 0;
84*4882a593Smuzhiyun }
85*4882a593Smuzhiyun 
phy_axg_mipi_pcie_analog_exit(struct phy * phy)86*4882a593Smuzhiyun static int phy_axg_mipi_pcie_analog_exit(struct phy *phy)
87*4882a593Smuzhiyun {
88*4882a593Smuzhiyun 	return 0;
89*4882a593Smuzhiyun }
90*4882a593Smuzhiyun 
91*4882a593Smuzhiyun static const struct phy_ops phy_axg_mipi_pcie_analog_ops = {
92*4882a593Smuzhiyun 	.init = phy_axg_mipi_pcie_analog_init,
93*4882a593Smuzhiyun 	.exit = phy_axg_mipi_pcie_analog_exit,
94*4882a593Smuzhiyun 	.power_on = phy_axg_mipi_pcie_analog_power_on,
95*4882a593Smuzhiyun 	.power_off = phy_axg_mipi_pcie_analog_power_off,
96*4882a593Smuzhiyun 	.owner = THIS_MODULE,
97*4882a593Smuzhiyun };
98*4882a593Smuzhiyun 
phy_axg_mipi_pcie_analog_xlate(struct device * dev,struct of_phandle_args * args)99*4882a593Smuzhiyun static struct phy *phy_axg_mipi_pcie_analog_xlate(struct device *dev,
100*4882a593Smuzhiyun 						  struct of_phandle_args *args)
101*4882a593Smuzhiyun {
102*4882a593Smuzhiyun 	struct phy_axg_mipi_pcie_analog_priv *priv = dev_get_drvdata(dev);
103*4882a593Smuzhiyun 	unsigned int mode;
104*4882a593Smuzhiyun 
105*4882a593Smuzhiyun 	if (args->args_count != 1) {
106*4882a593Smuzhiyun 		dev_err(dev, "invalid number of arguments\n");
107*4882a593Smuzhiyun 		return ERR_PTR(-EINVAL);
108*4882a593Smuzhiyun 	}
109*4882a593Smuzhiyun 
110*4882a593Smuzhiyun 	mode = args->args[0];
111*4882a593Smuzhiyun 
112*4882a593Smuzhiyun 	/* MIPI mode is not supported yet */
113*4882a593Smuzhiyun 	if (mode != PHY_TYPE_PCIE) {
114*4882a593Smuzhiyun 		dev_err(dev, "invalid phy mode select argument\n");
115*4882a593Smuzhiyun 		return ERR_PTR(-EINVAL);
116*4882a593Smuzhiyun 	}
117*4882a593Smuzhiyun 
118*4882a593Smuzhiyun 	priv->mode = mode;
119*4882a593Smuzhiyun 	return priv->phy;
120*4882a593Smuzhiyun }
121*4882a593Smuzhiyun 
phy_axg_mipi_pcie_analog_probe(struct platform_device * pdev)122*4882a593Smuzhiyun static int phy_axg_mipi_pcie_analog_probe(struct platform_device *pdev)
123*4882a593Smuzhiyun {
124*4882a593Smuzhiyun 	struct phy_provider *phy;
125*4882a593Smuzhiyun 	struct device *dev = &pdev->dev;
126*4882a593Smuzhiyun 	struct phy_axg_mipi_pcie_analog_priv *priv;
127*4882a593Smuzhiyun 	struct device_node *np = dev->of_node;
128*4882a593Smuzhiyun 	struct regmap *map;
129*4882a593Smuzhiyun 	struct resource *res;
130*4882a593Smuzhiyun 	void __iomem *base;
131*4882a593Smuzhiyun 	int ret;
132*4882a593Smuzhiyun 
133*4882a593Smuzhiyun 	priv = devm_kmalloc(dev, sizeof(*priv), GFP_KERNEL);
134*4882a593Smuzhiyun 	if (!priv)
135*4882a593Smuzhiyun 		return -ENOMEM;
136*4882a593Smuzhiyun 
137*4882a593Smuzhiyun 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
138*4882a593Smuzhiyun 	base = devm_ioremap_resource(dev, res);
139*4882a593Smuzhiyun 	if (IS_ERR(base)) {
140*4882a593Smuzhiyun 		dev_err(dev, "failed to get regmap base\n");
141*4882a593Smuzhiyun 		return PTR_ERR(base);
142*4882a593Smuzhiyun 	}
143*4882a593Smuzhiyun 
144*4882a593Smuzhiyun 	map = devm_regmap_init_mmio(dev, base,
145*4882a593Smuzhiyun 				    &phy_axg_mipi_pcie_analog_regmap_conf);
146*4882a593Smuzhiyun 	if (IS_ERR(map)) {
147*4882a593Smuzhiyun 		dev_err(dev, "failed to get HHI regmap\n");
148*4882a593Smuzhiyun 		return PTR_ERR(map);
149*4882a593Smuzhiyun 	}
150*4882a593Smuzhiyun 	priv->regmap = map;
151*4882a593Smuzhiyun 
152*4882a593Smuzhiyun 	priv->phy = devm_phy_create(dev, np, &phy_axg_mipi_pcie_analog_ops);
153*4882a593Smuzhiyun 	if (IS_ERR(priv->phy)) {
154*4882a593Smuzhiyun 		ret = PTR_ERR(priv->phy);
155*4882a593Smuzhiyun 		if (ret != -EPROBE_DEFER)
156*4882a593Smuzhiyun 			dev_err(dev, "failed to create PHY\n");
157*4882a593Smuzhiyun 		return ret;
158*4882a593Smuzhiyun 	}
159*4882a593Smuzhiyun 
160*4882a593Smuzhiyun 	phy_set_drvdata(priv->phy, priv);
161*4882a593Smuzhiyun 	dev_set_drvdata(dev, priv);
162*4882a593Smuzhiyun 
163*4882a593Smuzhiyun 	phy = devm_of_phy_provider_register(dev,
164*4882a593Smuzhiyun 					    phy_axg_mipi_pcie_analog_xlate);
165*4882a593Smuzhiyun 
166*4882a593Smuzhiyun 	return PTR_ERR_OR_ZERO(phy);
167*4882a593Smuzhiyun }
168*4882a593Smuzhiyun 
169*4882a593Smuzhiyun static const struct of_device_id phy_axg_mipi_pcie_analog_of_match[] = {
170*4882a593Smuzhiyun 	{
171*4882a593Smuzhiyun 		.compatible = "amlogic,axg-mipi-pcie-analog-phy",
172*4882a593Smuzhiyun 	},
173*4882a593Smuzhiyun 	{ },
174*4882a593Smuzhiyun };
175*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, phy_axg_mipi_pcie_analog_of_match);
176*4882a593Smuzhiyun 
177*4882a593Smuzhiyun static struct platform_driver phy_axg_mipi_pcie_analog_driver = {
178*4882a593Smuzhiyun 	.probe = phy_axg_mipi_pcie_analog_probe,
179*4882a593Smuzhiyun 	.driver = {
180*4882a593Smuzhiyun 		.name = "phy-axg-mipi-pcie-analog",
181*4882a593Smuzhiyun 		.of_match_table = phy_axg_mipi_pcie_analog_of_match,
182*4882a593Smuzhiyun 	},
183*4882a593Smuzhiyun };
184*4882a593Smuzhiyun module_platform_driver(phy_axg_mipi_pcie_analog_driver);
185*4882a593Smuzhiyun 
186*4882a593Smuzhiyun MODULE_AUTHOR("Remi Pommarel <repk@triplefau.lt>");
187*4882a593Smuzhiyun MODULE_DESCRIPTION("Amlogic AXG MIPI + PCIE analog PHY driver");
188*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
189