xref: /linux/drivers/phy/ralink/phy-mt7621-pci.c (revision 79790b6818e96c58fe2bffee1b418c16e64e7b80)
1d87da323SSergio Paracuellos // SPDX-License-Identifier: GPL-2.0+
2d87da323SSergio Paracuellos /*
3d87da323SSergio Paracuellos  * Mediatek MT7621 PCI PHY Driver
4d87da323SSergio Paracuellos  * Author: Sergio Paracuellos <sergio.paracuellos@gmail.com>
5d87da323SSergio Paracuellos  */
6d87da323SSergio Paracuellos 
7d87da323SSergio Paracuellos #include <dt-bindings/phy/phy.h>
860ece833SSergio Paracuellos #include <linux/clk.h>
9d87da323SSergio Paracuellos #include <linux/bitfield.h>
10d87da323SSergio Paracuellos #include <linux/bitops.h>
11d87da323SSergio Paracuellos #include <linux/module.h>
127559e757SRob Herring #include <linux/of.h>
13d87da323SSergio Paracuellos #include <linux/phy/phy.h>
14d87da323SSergio Paracuellos #include <linux/platform_device.h>
15d87da323SSergio Paracuellos #include <linux/regmap.h>
16d87da323SSergio Paracuellos #include <linux/sys_soc.h>
17d87da323SSergio Paracuellos 
18d87da323SSergio Paracuellos #define RG_PE1_PIPE_REG				0x02c
19d87da323SSergio Paracuellos #define RG_PE1_PIPE_RST				BIT(12)
20d87da323SSergio Paracuellos #define RG_PE1_PIPE_CMD_FRC			BIT(4)
21d87da323SSergio Paracuellos 
22d87da323SSergio Paracuellos #define RG_P0_TO_P1_WIDTH			0x100
23d87da323SSergio Paracuellos #define RG_PE1_H_LCDDS_REG			0x49c
24d87da323SSergio Paracuellos #define RG_PE1_H_LCDDS_PCW			GENMASK(30, 0)
25d87da323SSergio Paracuellos 
26d87da323SSergio Paracuellos #define RG_PE1_FRC_H_XTAL_REG			0x400
27d87da323SSergio Paracuellos #define RG_PE1_FRC_H_XTAL_TYPE			BIT(8)
28d87da323SSergio Paracuellos #define RG_PE1_H_XTAL_TYPE			GENMASK(10, 9)
29d87da323SSergio Paracuellos 
30d87da323SSergio Paracuellos #define RG_PE1_FRC_PHY_REG			0x000
31d87da323SSergio Paracuellos #define RG_PE1_FRC_PHY_EN			BIT(4)
32d87da323SSergio Paracuellos #define RG_PE1_PHY_EN				BIT(5)
33d87da323SSergio Paracuellos 
34d87da323SSergio Paracuellos #define RG_PE1_H_PLL_REG			0x490
35d87da323SSergio Paracuellos #define RG_PE1_H_PLL_BC				GENMASK(23, 22)
36d87da323SSergio Paracuellos #define RG_PE1_H_PLL_BP				GENMASK(21, 18)
37d87da323SSergio Paracuellos #define RG_PE1_H_PLL_IR				GENMASK(15, 12)
38d87da323SSergio Paracuellos #define RG_PE1_H_PLL_IC				GENMASK(11, 8)
39d87da323SSergio Paracuellos #define RG_PE1_H_PLL_PREDIV			GENMASK(7, 6)
40d87da323SSergio Paracuellos #define RG_PE1_PLL_DIVEN			GENMASK(3, 1)
41d87da323SSergio Paracuellos 
42d87da323SSergio Paracuellos #define RG_PE1_H_PLL_FBKSEL_REG			0x4bc
43d87da323SSergio Paracuellos #define RG_PE1_H_PLL_FBKSEL			GENMASK(5, 4)
44d87da323SSergio Paracuellos 
45d87da323SSergio Paracuellos #define	RG_PE1_H_LCDDS_SSC_PRD_REG		0x4a4
46d87da323SSergio Paracuellos #define RG_PE1_H_LCDDS_SSC_PRD			GENMASK(15, 0)
47d87da323SSergio Paracuellos 
48d87da323SSergio Paracuellos #define RG_PE1_H_LCDDS_SSC_DELTA_REG		0x4a8
49d87da323SSergio Paracuellos #define RG_PE1_H_LCDDS_SSC_DELTA		GENMASK(11, 0)
50d87da323SSergio Paracuellos #define RG_PE1_H_LCDDS_SSC_DELTA1		GENMASK(27, 16)
51d87da323SSergio Paracuellos 
52d87da323SSergio Paracuellos #define RG_PE1_LCDDS_CLK_PH_INV_REG		0x4a0
53d87da323SSergio Paracuellos #define RG_PE1_LCDDS_CLK_PH_INV			BIT(5)
54d87da323SSergio Paracuellos 
55d87da323SSergio Paracuellos #define RG_PE1_H_PLL_BR_REG			0x4ac
56d87da323SSergio Paracuellos #define RG_PE1_H_PLL_BR				GENMASK(18, 16)
57d87da323SSergio Paracuellos 
58d87da323SSergio Paracuellos #define	RG_PE1_MSTCKDIV_REG			0x414
59d87da323SSergio Paracuellos #define RG_PE1_MSTCKDIV				GENMASK(7, 6)
60d87da323SSergio Paracuellos 
61d87da323SSergio Paracuellos #define RG_PE1_FRC_MSTCKDIV			BIT(5)
62d87da323SSergio Paracuellos 
63d87da323SSergio Paracuellos #define MAX_PHYS	2
64d87da323SSergio Paracuellos 
65d87da323SSergio Paracuellos /**
66d87da323SSergio Paracuellos  * struct mt7621_pci_phy - Mt7621 Pcie PHY core
67d87da323SSergio Paracuellos  * @dev: pointer to device
68d87da323SSergio Paracuellos  * @regmap: kernel regmap pointer
69d87da323SSergio Paracuellos  * @phy: pointer to the kernel PHY device
7060ece833SSergio Paracuellos  * @sys_clk: pointer to the system XTAL clock
71d87da323SSergio Paracuellos  * @port_base: base register
72d87da323SSergio Paracuellos  * @has_dual_port: if the phy has dual ports.
73d87da323SSergio Paracuellos  * @bypass_pipe_rst: mark if 'mt7621_bypass_pipe_rst'
74d87da323SSergio Paracuellos  * needs to be executed. Depends on chip revision.
75d87da323SSergio Paracuellos  */
76d87da323SSergio Paracuellos struct mt7621_pci_phy {
77d87da323SSergio Paracuellos 	struct device *dev;
78d87da323SSergio Paracuellos 	struct regmap *regmap;
79d87da323SSergio Paracuellos 	struct phy *phy;
8060ece833SSergio Paracuellos 	struct clk *sys_clk;
81d87da323SSergio Paracuellos 	void __iomem *port_base;
82d87da323SSergio Paracuellos 	bool has_dual_port;
83d87da323SSergio Paracuellos 	bool bypass_pipe_rst;
84d87da323SSergio Paracuellos };
85d87da323SSergio Paracuellos 
mt7621_phy_rmw(struct mt7621_pci_phy * phy,u32 reg,u32 clr,u32 set)86d87da323SSergio Paracuellos static inline void mt7621_phy_rmw(struct mt7621_pci_phy *phy,
87d87da323SSergio Paracuellos 				  u32 reg, u32 clr, u32 set)
88d87da323SSergio Paracuellos {
89d87da323SSergio Paracuellos 	u32 val;
90d87da323SSergio Paracuellos 
91d87da323SSergio Paracuellos 	/*
92d87da323SSergio Paracuellos 	 * We cannot use 'regmap_write_bits' here because internally
93d87da323SSergio Paracuellos 	 * 'set' is masked before is set to the value that will be
94d87da323SSergio Paracuellos 	 * written to the register. That way results in no reliable
95d87da323SSergio Paracuellos 	 * pci setup. Avoid to mask 'set' before set value to 'val'
96d87da323SSergio Paracuellos 	 * completely avoid the problem.
97d87da323SSergio Paracuellos 	 */
98d87da323SSergio Paracuellos 	regmap_read(phy->regmap, reg, &val);
99d87da323SSergio Paracuellos 	val &= ~clr;
100d87da323SSergio Paracuellos 	val |= set;
101d87da323SSergio Paracuellos 	regmap_write(phy->regmap, reg, val);
102d87da323SSergio Paracuellos }
103d87da323SSergio Paracuellos 
mt7621_bypass_pipe_rst(struct mt7621_pci_phy * phy)104d87da323SSergio Paracuellos static void mt7621_bypass_pipe_rst(struct mt7621_pci_phy *phy)
105d87da323SSergio Paracuellos {
106d87da323SSergio Paracuellos 	mt7621_phy_rmw(phy, RG_PE1_PIPE_REG, 0, RG_PE1_PIPE_RST);
107d87da323SSergio Paracuellos 	mt7621_phy_rmw(phy, RG_PE1_PIPE_REG, 0, RG_PE1_PIPE_CMD_FRC);
108d87da323SSergio Paracuellos 
109d87da323SSergio Paracuellos 	if (phy->has_dual_port) {
110d87da323SSergio Paracuellos 		mt7621_phy_rmw(phy, RG_PE1_PIPE_REG + RG_P0_TO_P1_WIDTH,
111d87da323SSergio Paracuellos 			       0, RG_PE1_PIPE_RST);
112d87da323SSergio Paracuellos 		mt7621_phy_rmw(phy, RG_PE1_PIPE_REG + RG_P0_TO_P1_WIDTH,
113d87da323SSergio Paracuellos 			       0, RG_PE1_PIPE_CMD_FRC);
114d87da323SSergio Paracuellos 	}
115d87da323SSergio Paracuellos }
116d87da323SSergio Paracuellos 
mt7621_set_phy_for_ssc(struct mt7621_pci_phy * phy)11760ece833SSergio Paracuellos static int mt7621_set_phy_for_ssc(struct mt7621_pci_phy *phy)
118d87da323SSergio Paracuellos {
119d87da323SSergio Paracuellos 	struct device *dev = phy->dev;
12060ece833SSergio Paracuellos 	unsigned long clk_rate;
121d87da323SSergio Paracuellos 
12260ece833SSergio Paracuellos 	clk_rate = clk_get_rate(phy->sys_clk);
12360ece833SSergio Paracuellos 	if (!clk_rate)
12460ece833SSergio Paracuellos 		return -EINVAL;
125d87da323SSergio Paracuellos 
126d87da323SSergio Paracuellos 	/* Set PCIe Port PHY to disable SSC */
127d87da323SSergio Paracuellos 	/* Debug Xtal Type */
128d87da323SSergio Paracuellos 	mt7621_phy_rmw(phy, RG_PE1_FRC_H_XTAL_REG,
129d87da323SSergio Paracuellos 		       RG_PE1_FRC_H_XTAL_TYPE | RG_PE1_H_XTAL_TYPE,
130d87da323SSergio Paracuellos 		       RG_PE1_FRC_H_XTAL_TYPE |
131d87da323SSergio Paracuellos 		       FIELD_PREP(RG_PE1_H_XTAL_TYPE, 0x00));
132d87da323SSergio Paracuellos 
133d87da323SSergio Paracuellos 	/* disable port */
134d87da323SSergio Paracuellos 	mt7621_phy_rmw(phy, RG_PE1_FRC_PHY_REG, RG_PE1_PHY_EN,
135d87da323SSergio Paracuellos 		       RG_PE1_FRC_PHY_EN);
136d87da323SSergio Paracuellos 
137d87da323SSergio Paracuellos 	if (phy->has_dual_port) {
138d87da323SSergio Paracuellos 		mt7621_phy_rmw(phy, RG_PE1_FRC_PHY_REG + RG_P0_TO_P1_WIDTH,
139d87da323SSergio Paracuellos 			       RG_PE1_PHY_EN, RG_PE1_FRC_PHY_EN);
140d87da323SSergio Paracuellos 	}
141d87da323SSergio Paracuellos 
14260ece833SSergio Paracuellos 	if (clk_rate == 40000000) { /* 40MHz Xtal */
143d87da323SSergio Paracuellos 		/* Set Pre-divider ratio (for host mode) */
144d87da323SSergio Paracuellos 		mt7621_phy_rmw(phy, RG_PE1_H_PLL_REG, RG_PE1_H_PLL_PREDIV,
145d87da323SSergio Paracuellos 			       FIELD_PREP(RG_PE1_H_PLL_PREDIV, 0x01));
146d87da323SSergio Paracuellos 
147d87da323SSergio Paracuellos 		dev_dbg(dev, "Xtal is 40MHz\n");
14860ece833SSergio Paracuellos 	} else if (clk_rate == 25000000) { /* 25MHz Xal */
149d87da323SSergio Paracuellos 		mt7621_phy_rmw(phy, RG_PE1_H_PLL_REG, RG_PE1_H_PLL_PREDIV,
150d87da323SSergio Paracuellos 			       FIELD_PREP(RG_PE1_H_PLL_PREDIV, 0x00));
151d87da323SSergio Paracuellos 
152d87da323SSergio Paracuellos 		/* Select feedback clock */
153d87da323SSergio Paracuellos 		mt7621_phy_rmw(phy, RG_PE1_H_PLL_FBKSEL_REG,
154d87da323SSergio Paracuellos 			       RG_PE1_H_PLL_FBKSEL,
155d87da323SSergio Paracuellos 			       FIELD_PREP(RG_PE1_H_PLL_FBKSEL, 0x01));
156d87da323SSergio Paracuellos 
157d87da323SSergio Paracuellos 		/* DDS NCPO PCW (for host mode) */
158d87da323SSergio Paracuellos 		mt7621_phy_rmw(phy, RG_PE1_H_LCDDS_SSC_PRD_REG,
159d87da323SSergio Paracuellos 			       RG_PE1_H_LCDDS_SSC_PRD,
160d87da323SSergio Paracuellos 			       FIELD_PREP(RG_PE1_H_LCDDS_SSC_PRD, 0x00));
161d87da323SSergio Paracuellos 
162d87da323SSergio Paracuellos 		/* DDS SSC dither period control */
163d87da323SSergio Paracuellos 		mt7621_phy_rmw(phy, RG_PE1_H_LCDDS_SSC_PRD_REG,
164d87da323SSergio Paracuellos 			       RG_PE1_H_LCDDS_SSC_PRD,
165d87da323SSergio Paracuellos 			       FIELD_PREP(RG_PE1_H_LCDDS_SSC_PRD, 0x18d));
166d87da323SSergio Paracuellos 
167d87da323SSergio Paracuellos 		/* DDS SSC dither amplitude control */
168d87da323SSergio Paracuellos 		mt7621_phy_rmw(phy, RG_PE1_H_LCDDS_SSC_DELTA_REG,
169d87da323SSergio Paracuellos 			       RG_PE1_H_LCDDS_SSC_DELTA |
170d87da323SSergio Paracuellos 			       RG_PE1_H_LCDDS_SSC_DELTA1,
171d87da323SSergio Paracuellos 			       FIELD_PREP(RG_PE1_H_LCDDS_SSC_DELTA, 0x4a) |
172d87da323SSergio Paracuellos 			       FIELD_PREP(RG_PE1_H_LCDDS_SSC_DELTA1, 0x4a));
173d87da323SSergio Paracuellos 
174d87da323SSergio Paracuellos 		dev_dbg(dev, "Xtal is 25MHz\n");
175d87da323SSergio Paracuellos 	} else { /* 20MHz Xtal */
176d87da323SSergio Paracuellos 		mt7621_phy_rmw(phy, RG_PE1_H_PLL_REG, RG_PE1_H_PLL_PREDIV,
177d87da323SSergio Paracuellos 			       FIELD_PREP(RG_PE1_H_PLL_PREDIV, 0x00));
178d87da323SSergio Paracuellos 
179d87da323SSergio Paracuellos 		dev_dbg(dev, "Xtal is 20MHz\n");
180d87da323SSergio Paracuellos 	}
181d87da323SSergio Paracuellos 
182d87da323SSergio Paracuellos 	/* DDS clock inversion */
183d87da323SSergio Paracuellos 	mt7621_phy_rmw(phy, RG_PE1_LCDDS_CLK_PH_INV_REG,
184d87da323SSergio Paracuellos 		       RG_PE1_LCDDS_CLK_PH_INV, RG_PE1_LCDDS_CLK_PH_INV);
185d87da323SSergio Paracuellos 
186d87da323SSergio Paracuellos 	/* Set PLL bits */
187d87da323SSergio Paracuellos 	mt7621_phy_rmw(phy, RG_PE1_H_PLL_REG,
188d87da323SSergio Paracuellos 		       RG_PE1_H_PLL_BC | RG_PE1_H_PLL_BP | RG_PE1_H_PLL_IR |
189d87da323SSergio Paracuellos 		       RG_PE1_H_PLL_IC | RG_PE1_PLL_DIVEN,
190d87da323SSergio Paracuellos 		       FIELD_PREP(RG_PE1_H_PLL_BC, 0x02) |
191d87da323SSergio Paracuellos 		       FIELD_PREP(RG_PE1_H_PLL_BP, 0x06) |
192d87da323SSergio Paracuellos 		       FIELD_PREP(RG_PE1_H_PLL_IR, 0x02) |
193d87da323SSergio Paracuellos 		       FIELD_PREP(RG_PE1_H_PLL_IC, 0x01) |
194d87da323SSergio Paracuellos 		       FIELD_PREP(RG_PE1_PLL_DIVEN, 0x02));
195d87da323SSergio Paracuellos 
196d87da323SSergio Paracuellos 	mt7621_phy_rmw(phy, RG_PE1_H_PLL_BR_REG, RG_PE1_H_PLL_BR,
197d87da323SSergio Paracuellos 		       FIELD_PREP(RG_PE1_H_PLL_BR, 0x00));
198d87da323SSergio Paracuellos 
19960ece833SSergio Paracuellos 	if (clk_rate == 40000000) { /* 40MHz Xtal */
200d87da323SSergio Paracuellos 		/* set force mode enable of da_pe1_mstckdiv */
201d87da323SSergio Paracuellos 		mt7621_phy_rmw(phy, RG_PE1_MSTCKDIV_REG,
202d87da323SSergio Paracuellos 			       RG_PE1_MSTCKDIV | RG_PE1_FRC_MSTCKDIV,
203d87da323SSergio Paracuellos 			       FIELD_PREP(RG_PE1_MSTCKDIV, 0x01) |
204d87da323SSergio Paracuellos 			       RG_PE1_FRC_MSTCKDIV);
205d87da323SSergio Paracuellos 	}
20660ece833SSergio Paracuellos 
20760ece833SSergio Paracuellos 	return 0;
208d87da323SSergio Paracuellos }
209d87da323SSergio Paracuellos 
mt7621_pci_phy_init(struct phy * phy)210d87da323SSergio Paracuellos static int mt7621_pci_phy_init(struct phy *phy)
211d87da323SSergio Paracuellos {
212d87da323SSergio Paracuellos 	struct mt7621_pci_phy *mphy = phy_get_drvdata(phy);
213d87da323SSergio Paracuellos 
214d87da323SSergio Paracuellos 	if (mphy->bypass_pipe_rst)
215d87da323SSergio Paracuellos 		mt7621_bypass_pipe_rst(mphy);
216d87da323SSergio Paracuellos 
21760ece833SSergio Paracuellos 	return mt7621_set_phy_for_ssc(mphy);
218d87da323SSergio Paracuellos }
219d87da323SSergio Paracuellos 
mt7621_pci_phy_power_on(struct phy * phy)220d87da323SSergio Paracuellos static int mt7621_pci_phy_power_on(struct phy *phy)
221d87da323SSergio Paracuellos {
222d87da323SSergio Paracuellos 	struct mt7621_pci_phy *mphy = phy_get_drvdata(phy);
223d87da323SSergio Paracuellos 
224d87da323SSergio Paracuellos 	/* Enable PHY and disable force mode */
225d87da323SSergio Paracuellos 	mt7621_phy_rmw(mphy, RG_PE1_FRC_PHY_REG,
226d87da323SSergio Paracuellos 		       RG_PE1_FRC_PHY_EN, RG_PE1_PHY_EN);
227d87da323SSergio Paracuellos 
228d87da323SSergio Paracuellos 	if (mphy->has_dual_port) {
229d87da323SSergio Paracuellos 		mt7621_phy_rmw(mphy, RG_PE1_FRC_PHY_REG + RG_P0_TO_P1_WIDTH,
230d87da323SSergio Paracuellos 			       RG_PE1_FRC_PHY_EN, RG_PE1_PHY_EN);
231d87da323SSergio Paracuellos 	}
232d87da323SSergio Paracuellos 
233d87da323SSergio Paracuellos 	return 0;
234d87da323SSergio Paracuellos }
235d87da323SSergio Paracuellos 
mt7621_pci_phy_power_off(struct phy * phy)236d87da323SSergio Paracuellos static int mt7621_pci_phy_power_off(struct phy *phy)
237d87da323SSergio Paracuellos {
238d87da323SSergio Paracuellos 	struct mt7621_pci_phy *mphy = phy_get_drvdata(phy);
239d87da323SSergio Paracuellos 
240d87da323SSergio Paracuellos 	/* Disable PHY */
241d87da323SSergio Paracuellos 	mt7621_phy_rmw(mphy, RG_PE1_FRC_PHY_REG,
242d87da323SSergio Paracuellos 		       RG_PE1_PHY_EN, RG_PE1_FRC_PHY_EN);
243d87da323SSergio Paracuellos 
244d87da323SSergio Paracuellos 	if (mphy->has_dual_port) {
245d87da323SSergio Paracuellos 		mt7621_phy_rmw(mphy, RG_PE1_FRC_PHY_REG + RG_P0_TO_P1_WIDTH,
246d87da323SSergio Paracuellos 			       RG_PE1_PHY_EN, RG_PE1_FRC_PHY_EN);
247d87da323SSergio Paracuellos 	}
248d87da323SSergio Paracuellos 
249d87da323SSergio Paracuellos 	return 0;
250d87da323SSergio Paracuellos }
251d87da323SSergio Paracuellos 
mt7621_pci_phy_exit(struct phy * phy)252d87da323SSergio Paracuellos static int mt7621_pci_phy_exit(struct phy *phy)
253d87da323SSergio Paracuellos {
254d87da323SSergio Paracuellos 	return 0;
255d87da323SSergio Paracuellos }
256d87da323SSergio Paracuellos 
257d87da323SSergio Paracuellos static const struct phy_ops mt7621_pci_phy_ops = {
258d87da323SSergio Paracuellos 	.init		= mt7621_pci_phy_init,
259d87da323SSergio Paracuellos 	.exit		= mt7621_pci_phy_exit,
260d87da323SSergio Paracuellos 	.power_on	= mt7621_pci_phy_power_on,
261d87da323SSergio Paracuellos 	.power_off	= mt7621_pci_phy_power_off,
262d87da323SSergio Paracuellos 	.owner		= THIS_MODULE,
263d87da323SSergio Paracuellos };
264d87da323SSergio Paracuellos 
mt7621_pcie_phy_of_xlate(struct device * dev,const struct of_phandle_args * args)265d87da323SSergio Paracuellos static struct phy *mt7621_pcie_phy_of_xlate(struct device *dev,
266*00ca8a15SKrzysztof Kozlowski 					    const struct of_phandle_args *args)
267d87da323SSergio Paracuellos {
268d87da323SSergio Paracuellos 	struct mt7621_pci_phy *mt7621_phy = dev_get_drvdata(dev);
269d87da323SSergio Paracuellos 
270d87da323SSergio Paracuellos 	if (WARN_ON(args->args[0] >= MAX_PHYS))
271d87da323SSergio Paracuellos 		return ERR_PTR(-ENODEV);
272d87da323SSergio Paracuellos 
273d87da323SSergio Paracuellos 	mt7621_phy->has_dual_port = args->args[0];
274d87da323SSergio Paracuellos 
275652a6a2eSSergio Paracuellos 	dev_dbg(dev, "PHY for 0x%px (dual port = %d)\n",
276652a6a2eSSergio Paracuellos 		mt7621_phy->port_base, mt7621_phy->has_dual_port);
277d87da323SSergio Paracuellos 
278d87da323SSergio Paracuellos 	return mt7621_phy->phy;
279d87da323SSergio Paracuellos }
280d87da323SSergio Paracuellos 
281d87da323SSergio Paracuellos static const struct soc_device_attribute mt7621_pci_quirks_match[] = {
282819b885cSJohn Thomson 	{ .soc_id = "mt7621", .revision = "E2" },
283819b885cSJohn Thomson 	{ /* sentinel */ }
284d87da323SSergio Paracuellos };
285d87da323SSergio Paracuellos 
286d87da323SSergio Paracuellos static const struct regmap_config mt7621_pci_phy_regmap_config = {
287d87da323SSergio Paracuellos 	.reg_bits = 32,
288d87da323SSergio Paracuellos 	.val_bits = 32,
289d87da323SSergio Paracuellos 	.reg_stride = 4,
290d87da323SSergio Paracuellos 	.max_register = 0x700,
291d87da323SSergio Paracuellos };
292d87da323SSergio Paracuellos 
mt7621_pci_phy_probe(struct platform_device * pdev)293d87da323SSergio Paracuellos static int mt7621_pci_phy_probe(struct platform_device *pdev)
294d87da323SSergio Paracuellos {
295d87da323SSergio Paracuellos 	struct device *dev = &pdev->dev;
296d87da323SSergio Paracuellos 	const struct soc_device_attribute *attr;
297d87da323SSergio Paracuellos 	struct phy_provider *provider;
298d87da323SSergio Paracuellos 	struct mt7621_pci_phy *phy;
299d87da323SSergio Paracuellos 
300d87da323SSergio Paracuellos 	phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);
301d87da323SSergio Paracuellos 	if (!phy)
302d87da323SSergio Paracuellos 		return -ENOMEM;
303d87da323SSergio Paracuellos 
304d87da323SSergio Paracuellos 	attr = soc_device_match(mt7621_pci_quirks_match);
305d87da323SSergio Paracuellos 	if (attr)
306d87da323SSergio Paracuellos 		phy->bypass_pipe_rst = true;
307d87da323SSergio Paracuellos 
308d87da323SSergio Paracuellos 	phy->dev = dev;
309d87da323SSergio Paracuellos 	platform_set_drvdata(pdev, phy);
310d87da323SSergio Paracuellos 
311d87da323SSergio Paracuellos 	phy->port_base = devm_platform_ioremap_resource(pdev, 0);
312d87da323SSergio Paracuellos 	if (IS_ERR(phy->port_base)) {
313d87da323SSergio Paracuellos 		dev_err(dev, "failed to remap phy regs\n");
314d87da323SSergio Paracuellos 		return PTR_ERR(phy->port_base);
315d87da323SSergio Paracuellos 	}
316d87da323SSergio Paracuellos 
317d87da323SSergio Paracuellos 	phy->regmap = devm_regmap_init_mmio(phy->dev, phy->port_base,
318d87da323SSergio Paracuellos 					    &mt7621_pci_phy_regmap_config);
319d87da323SSergio Paracuellos 	if (IS_ERR(phy->regmap))
320d87da323SSergio Paracuellos 		return PTR_ERR(phy->regmap);
321d87da323SSergio Paracuellos 
322d87da323SSergio Paracuellos 	phy->phy = devm_phy_create(dev, dev->of_node, &mt7621_pci_phy_ops);
323b976c987SWei Yongjun 	if (IS_ERR(phy->phy)) {
324d87da323SSergio Paracuellos 		dev_err(dev, "failed to create phy\n");
325b976c987SWei Yongjun 		return PTR_ERR(phy->phy);
326d87da323SSergio Paracuellos 	}
327d87da323SSergio Paracuellos 
32860ece833SSergio Paracuellos 	phy->sys_clk = devm_clk_get(dev, NULL);
32960ece833SSergio Paracuellos 	if (IS_ERR(phy->sys_clk)) {
33060ece833SSergio Paracuellos 		dev_err(dev, "failed to get phy clock\n");
33160ece833SSergio Paracuellos 		return PTR_ERR(phy->sys_clk);
33260ece833SSergio Paracuellos 	}
33360ece833SSergio Paracuellos 
334d87da323SSergio Paracuellos 	phy_set_drvdata(phy->phy, phy);
335d87da323SSergio Paracuellos 
336d87da323SSergio Paracuellos 	provider = devm_of_phy_provider_register(dev, mt7621_pcie_phy_of_xlate);
337d87da323SSergio Paracuellos 
338d87da323SSergio Paracuellos 	return PTR_ERR_OR_ZERO(provider);
339d87da323SSergio Paracuellos }
340d87da323SSergio Paracuellos 
341d87da323SSergio Paracuellos static const struct of_device_id mt7621_pci_phy_ids[] = {
342d87da323SSergio Paracuellos 	{ .compatible = "mediatek,mt7621-pci-phy" },
343d87da323SSergio Paracuellos 	{},
344d87da323SSergio Paracuellos };
3458145dcb0SSergio Paracuellos MODULE_DEVICE_TABLE(of, mt7621_pci_phy_ids);
346d87da323SSergio Paracuellos 
347d87da323SSergio Paracuellos static struct platform_driver mt7621_pci_phy_driver = {
348d87da323SSergio Paracuellos 	.probe = mt7621_pci_phy_probe,
349d87da323SSergio Paracuellos 	.driver = {
350d87da323SSergio Paracuellos 		.name = "mt7621-pci-phy",
351d6e9e8e5SSergio Paracuellos 		.of_match_table = mt7621_pci_phy_ids,
352d87da323SSergio Paracuellos 	},
353d87da323SSergio Paracuellos };
354d87da323SSergio Paracuellos 
355d87da323SSergio Paracuellos builtin_platform_driver(mt7621_pci_phy_driver);
356d87da323SSergio Paracuellos 
357d87da323SSergio Paracuellos MODULE_AUTHOR("Sergio Paracuellos <sergio.paracuellos@gmail.com>");
358d87da323SSergio Paracuellos MODULE_DESCRIPTION("MediaTek MT7621 PCIe PHY driver");
359d87da323SSergio Paracuellos MODULE_LICENSE("GPL v2");
360