xref: /OK3568_Linux_fs/kernel/drivers/phy/marvell/phy-pxa-28nm-hsic.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Copyright (C) 2015 Linaro, Ltd.
4*4882a593Smuzhiyun  * Rob Herring <robh@kernel.org>
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  * Based on vendor driver:
7*4882a593Smuzhiyun  * Copyright (C) 2013 Marvell Inc.
8*4882a593Smuzhiyun  * Author: Chao Xie <xiechao.mail@gmail.com>
9*4882a593Smuzhiyun  */
10*4882a593Smuzhiyun 
11*4882a593Smuzhiyun #include <linux/delay.h>
12*4882a593Smuzhiyun #include <linux/slab.h>
13*4882a593Smuzhiyun #include <linux/of.h>
14*4882a593Smuzhiyun #include <linux/io.h>
15*4882a593Smuzhiyun #include <linux/iopoll.h>
16*4882a593Smuzhiyun #include <linux/err.h>
17*4882a593Smuzhiyun #include <linux/clk.h>
18*4882a593Smuzhiyun #include <linux/module.h>
19*4882a593Smuzhiyun #include <linux/platform_device.h>
20*4882a593Smuzhiyun #include <linux/phy/phy.h>
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun #define PHY_28NM_HSIC_CTRL			0x08
23*4882a593Smuzhiyun #define PHY_28NM_HSIC_IMPCAL_CAL		0x18
24*4882a593Smuzhiyun #define PHY_28NM_HSIC_PLL_CTRL01		0x1c
25*4882a593Smuzhiyun #define PHY_28NM_HSIC_PLL_CTRL2			0x20
26*4882a593Smuzhiyun #define PHY_28NM_HSIC_INT			0x28
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun #define PHY_28NM_HSIC_PLL_SELLPFR_SHIFT		26
29*4882a593Smuzhiyun #define PHY_28NM_HSIC_PLL_FBDIV_SHIFT		0
30*4882a593Smuzhiyun #define PHY_28NM_HSIC_PLL_REFDIV_SHIFT		9
31*4882a593Smuzhiyun 
32*4882a593Smuzhiyun #define PHY_28NM_HSIC_S2H_PU_PLL		BIT(10)
33*4882a593Smuzhiyun #define PHY_28NM_HSIC_H2S_PLL_LOCK		BIT(15)
34*4882a593Smuzhiyun #define PHY_28NM_HSIC_S2H_HSIC_EN		BIT(7)
35*4882a593Smuzhiyun #define S2H_DRV_SE0_4RESUME			BIT(14)
36*4882a593Smuzhiyun #define PHY_28NM_HSIC_H2S_IMPCAL_DONE		BIT(27)
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun #define PHY_28NM_HSIC_CONNECT_INT		BIT(1)
39*4882a593Smuzhiyun #define PHY_28NM_HSIC_HS_READY_INT		BIT(2)
40*4882a593Smuzhiyun 
41*4882a593Smuzhiyun struct mv_hsic_phy {
42*4882a593Smuzhiyun 	struct phy		*phy;
43*4882a593Smuzhiyun 	struct platform_device	*pdev;
44*4882a593Smuzhiyun 	void __iomem		*base;
45*4882a593Smuzhiyun 	struct clk		*clk;
46*4882a593Smuzhiyun };
47*4882a593Smuzhiyun 
wait_for_reg(void __iomem * reg,u32 mask,u32 ms)48*4882a593Smuzhiyun static int wait_for_reg(void __iomem *reg, u32 mask, u32 ms)
49*4882a593Smuzhiyun {
50*4882a593Smuzhiyun 	u32 val;
51*4882a593Smuzhiyun 
52*4882a593Smuzhiyun 	return readl_poll_timeout(reg, val, ((val & mask) == mask),
53*4882a593Smuzhiyun 				  1000, 1000 * ms);
54*4882a593Smuzhiyun }
55*4882a593Smuzhiyun 
mv_hsic_phy_init(struct phy * phy)56*4882a593Smuzhiyun static int mv_hsic_phy_init(struct phy *phy)
57*4882a593Smuzhiyun {
58*4882a593Smuzhiyun 	struct mv_hsic_phy *mv_phy = phy_get_drvdata(phy);
59*4882a593Smuzhiyun 	struct platform_device *pdev = mv_phy->pdev;
60*4882a593Smuzhiyun 	void __iomem *base = mv_phy->base;
61*4882a593Smuzhiyun 	int ret;
62*4882a593Smuzhiyun 
63*4882a593Smuzhiyun 	clk_prepare_enable(mv_phy->clk);
64*4882a593Smuzhiyun 
65*4882a593Smuzhiyun 	/* Set reference clock */
66*4882a593Smuzhiyun 	writel(0x1 << PHY_28NM_HSIC_PLL_SELLPFR_SHIFT |
67*4882a593Smuzhiyun 		0xf0 << PHY_28NM_HSIC_PLL_FBDIV_SHIFT |
68*4882a593Smuzhiyun 		0xd << PHY_28NM_HSIC_PLL_REFDIV_SHIFT,
69*4882a593Smuzhiyun 		base + PHY_28NM_HSIC_PLL_CTRL01);
70*4882a593Smuzhiyun 
71*4882a593Smuzhiyun 	/* Turn on PLL */
72*4882a593Smuzhiyun 	writel(readl(base + PHY_28NM_HSIC_PLL_CTRL2) |
73*4882a593Smuzhiyun 		PHY_28NM_HSIC_S2H_PU_PLL,
74*4882a593Smuzhiyun 		base + PHY_28NM_HSIC_PLL_CTRL2);
75*4882a593Smuzhiyun 
76*4882a593Smuzhiyun 	/* Make sure PHY PLL is locked */
77*4882a593Smuzhiyun 	ret = wait_for_reg(base + PHY_28NM_HSIC_PLL_CTRL2,
78*4882a593Smuzhiyun 			   PHY_28NM_HSIC_H2S_PLL_LOCK, 100);
79*4882a593Smuzhiyun 	if (ret) {
80*4882a593Smuzhiyun 		dev_err(&pdev->dev, "HSIC PHY PLL not locked after 100mS.");
81*4882a593Smuzhiyun 		clk_disable_unprepare(mv_phy->clk);
82*4882a593Smuzhiyun 	}
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun 	return ret;
85*4882a593Smuzhiyun }
86*4882a593Smuzhiyun 
mv_hsic_phy_power_on(struct phy * phy)87*4882a593Smuzhiyun static int mv_hsic_phy_power_on(struct phy *phy)
88*4882a593Smuzhiyun {
89*4882a593Smuzhiyun 	struct mv_hsic_phy *mv_phy = phy_get_drvdata(phy);
90*4882a593Smuzhiyun 	struct platform_device *pdev = mv_phy->pdev;
91*4882a593Smuzhiyun 	void __iomem *base = mv_phy->base;
92*4882a593Smuzhiyun 	u32 reg;
93*4882a593Smuzhiyun 	int ret;
94*4882a593Smuzhiyun 
95*4882a593Smuzhiyun 	reg = readl(base + PHY_28NM_HSIC_CTRL);
96*4882a593Smuzhiyun 	/* Avoid SE0 state when resume for some device will take it as reset */
97*4882a593Smuzhiyun 	reg &= ~S2H_DRV_SE0_4RESUME;
98*4882a593Smuzhiyun 	reg |= PHY_28NM_HSIC_S2H_HSIC_EN;	/* Enable HSIC PHY */
99*4882a593Smuzhiyun 	writel(reg, base + PHY_28NM_HSIC_CTRL);
100*4882a593Smuzhiyun 
101*4882a593Smuzhiyun 	/*
102*4882a593Smuzhiyun 	 *  Calibration Timing
103*4882a593Smuzhiyun 	 *		   ____________________________
104*4882a593Smuzhiyun 	 *  CAL START   ___|
105*4882a593Smuzhiyun 	 *			   ____________________
106*4882a593Smuzhiyun 	 *  CAL_DONE    ___________|
107*4882a593Smuzhiyun 	 *		   | 400us |
108*4882a593Smuzhiyun 	 */
109*4882a593Smuzhiyun 
110*4882a593Smuzhiyun 	/* Make sure PHY Calibration is ready */
111*4882a593Smuzhiyun 	ret = wait_for_reg(base + PHY_28NM_HSIC_IMPCAL_CAL,
112*4882a593Smuzhiyun 			   PHY_28NM_HSIC_H2S_IMPCAL_DONE, 100);
113*4882a593Smuzhiyun 	if (ret) {
114*4882a593Smuzhiyun 		dev_warn(&pdev->dev, "HSIC PHY READY not set after 100mS.");
115*4882a593Smuzhiyun 		return ret;
116*4882a593Smuzhiyun 	}
117*4882a593Smuzhiyun 
118*4882a593Smuzhiyun 	/* Waiting for HSIC connect int*/
119*4882a593Smuzhiyun 	ret = wait_for_reg(base + PHY_28NM_HSIC_INT,
120*4882a593Smuzhiyun 			   PHY_28NM_HSIC_CONNECT_INT, 200);
121*4882a593Smuzhiyun 	if (ret)
122*4882a593Smuzhiyun 		dev_warn(&pdev->dev, "HSIC wait for connect interrupt timeout.");
123*4882a593Smuzhiyun 
124*4882a593Smuzhiyun 	return ret;
125*4882a593Smuzhiyun }
126*4882a593Smuzhiyun 
mv_hsic_phy_power_off(struct phy * phy)127*4882a593Smuzhiyun static int mv_hsic_phy_power_off(struct phy *phy)
128*4882a593Smuzhiyun {
129*4882a593Smuzhiyun 	struct mv_hsic_phy *mv_phy = phy_get_drvdata(phy);
130*4882a593Smuzhiyun 	void __iomem *base = mv_phy->base;
131*4882a593Smuzhiyun 
132*4882a593Smuzhiyun 	writel(readl(base + PHY_28NM_HSIC_CTRL) & ~PHY_28NM_HSIC_S2H_HSIC_EN,
133*4882a593Smuzhiyun 		base + PHY_28NM_HSIC_CTRL);
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun 	return 0;
136*4882a593Smuzhiyun }
137*4882a593Smuzhiyun 
mv_hsic_phy_exit(struct phy * phy)138*4882a593Smuzhiyun static int mv_hsic_phy_exit(struct phy *phy)
139*4882a593Smuzhiyun {
140*4882a593Smuzhiyun 	struct mv_hsic_phy *mv_phy = phy_get_drvdata(phy);
141*4882a593Smuzhiyun 	void __iomem *base = mv_phy->base;
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun 	/* Turn off PLL */
144*4882a593Smuzhiyun 	writel(readl(base + PHY_28NM_HSIC_PLL_CTRL2) &
145*4882a593Smuzhiyun 		~PHY_28NM_HSIC_S2H_PU_PLL,
146*4882a593Smuzhiyun 		base + PHY_28NM_HSIC_PLL_CTRL2);
147*4882a593Smuzhiyun 
148*4882a593Smuzhiyun 	clk_disable_unprepare(mv_phy->clk);
149*4882a593Smuzhiyun 	return 0;
150*4882a593Smuzhiyun }
151*4882a593Smuzhiyun 
152*4882a593Smuzhiyun 
153*4882a593Smuzhiyun static const struct phy_ops hsic_ops = {
154*4882a593Smuzhiyun 	.init		= mv_hsic_phy_init,
155*4882a593Smuzhiyun 	.power_on	= mv_hsic_phy_power_on,
156*4882a593Smuzhiyun 	.power_off	= mv_hsic_phy_power_off,
157*4882a593Smuzhiyun 	.exit		= mv_hsic_phy_exit,
158*4882a593Smuzhiyun 	.owner		= THIS_MODULE,
159*4882a593Smuzhiyun };
160*4882a593Smuzhiyun 
mv_hsic_phy_probe(struct platform_device * pdev)161*4882a593Smuzhiyun static int mv_hsic_phy_probe(struct platform_device *pdev)
162*4882a593Smuzhiyun {
163*4882a593Smuzhiyun 	struct phy_provider *phy_provider;
164*4882a593Smuzhiyun 	struct mv_hsic_phy *mv_phy;
165*4882a593Smuzhiyun 	struct resource *r;
166*4882a593Smuzhiyun 
167*4882a593Smuzhiyun 	mv_phy = devm_kzalloc(&pdev->dev, sizeof(*mv_phy), GFP_KERNEL);
168*4882a593Smuzhiyun 	if (!mv_phy)
169*4882a593Smuzhiyun 		return -ENOMEM;
170*4882a593Smuzhiyun 
171*4882a593Smuzhiyun 	mv_phy->pdev = pdev;
172*4882a593Smuzhiyun 
173*4882a593Smuzhiyun 	mv_phy->clk = devm_clk_get(&pdev->dev, NULL);
174*4882a593Smuzhiyun 	if (IS_ERR(mv_phy->clk)) {
175*4882a593Smuzhiyun 		dev_err(&pdev->dev, "failed to get clock.\n");
176*4882a593Smuzhiyun 		return PTR_ERR(mv_phy->clk);
177*4882a593Smuzhiyun 	}
178*4882a593Smuzhiyun 
179*4882a593Smuzhiyun 	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
180*4882a593Smuzhiyun 	mv_phy->base = devm_ioremap_resource(&pdev->dev, r);
181*4882a593Smuzhiyun 	if (IS_ERR(mv_phy->base))
182*4882a593Smuzhiyun 		return PTR_ERR(mv_phy->base);
183*4882a593Smuzhiyun 
184*4882a593Smuzhiyun 	mv_phy->phy = devm_phy_create(&pdev->dev, pdev->dev.of_node, &hsic_ops);
185*4882a593Smuzhiyun 	if (IS_ERR(mv_phy->phy))
186*4882a593Smuzhiyun 		return PTR_ERR(mv_phy->phy);
187*4882a593Smuzhiyun 
188*4882a593Smuzhiyun 	phy_set_drvdata(mv_phy->phy, mv_phy);
189*4882a593Smuzhiyun 
190*4882a593Smuzhiyun 	phy_provider = devm_of_phy_provider_register(&pdev->dev, of_phy_simple_xlate);
191*4882a593Smuzhiyun 	return PTR_ERR_OR_ZERO(phy_provider);
192*4882a593Smuzhiyun }
193*4882a593Smuzhiyun 
194*4882a593Smuzhiyun static const struct of_device_id mv_hsic_phy_dt_match[] = {
195*4882a593Smuzhiyun 	{ .compatible = "marvell,pxa1928-hsic-phy", },
196*4882a593Smuzhiyun 	{},
197*4882a593Smuzhiyun };
198*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, mv_hsic_phy_dt_match);
199*4882a593Smuzhiyun 
200*4882a593Smuzhiyun static struct platform_driver mv_hsic_phy_driver = {
201*4882a593Smuzhiyun 	.probe	= mv_hsic_phy_probe,
202*4882a593Smuzhiyun 	.driver = {
203*4882a593Smuzhiyun 		.name   = "mv-hsic-phy",
204*4882a593Smuzhiyun 		.of_match_table = of_match_ptr(mv_hsic_phy_dt_match),
205*4882a593Smuzhiyun 	},
206*4882a593Smuzhiyun };
207*4882a593Smuzhiyun module_platform_driver(mv_hsic_phy_driver);
208*4882a593Smuzhiyun 
209*4882a593Smuzhiyun MODULE_AUTHOR("Rob Herring <robh@kernel.org>");
210*4882a593Smuzhiyun MODULE_DESCRIPTION("Marvell HSIC phy driver");
211*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
212