xref: /linux/drivers/phy/renesas/phy-rcar-gen3-usb3.c (revision 7c7356bab8e85c8d2e335752dcb89d94fe10d660)
1*7c7356baSYoshihiro Shimoda /*
2*7c7356baSYoshihiro Shimoda  * Renesas R-Car Gen3 for USB3.0 PHY driver
3*7c7356baSYoshihiro Shimoda  *
4*7c7356baSYoshihiro Shimoda  * Copyright (C) 2017 Renesas Electronics Corporation
5*7c7356baSYoshihiro Shimoda  *
6*7c7356baSYoshihiro Shimoda  * This program is free software; you can redistribute it and/or modify
7*7c7356baSYoshihiro Shimoda  * it under the terms of the GNU General Public License version 2 as
8*7c7356baSYoshihiro Shimoda  * published by the Free Software Foundation.
9*7c7356baSYoshihiro Shimoda  */
10*7c7356baSYoshihiro Shimoda 
11*7c7356baSYoshihiro Shimoda #include <linux/clk.h>
12*7c7356baSYoshihiro Shimoda #include <linux/delay.h>
13*7c7356baSYoshihiro Shimoda #include <linux/io.h>
14*7c7356baSYoshihiro Shimoda #include <linux/module.h>
15*7c7356baSYoshihiro Shimoda #include <linux/of.h>
16*7c7356baSYoshihiro Shimoda #include <linux/phy/phy.h>
17*7c7356baSYoshihiro Shimoda #include <linux/platform_device.h>
18*7c7356baSYoshihiro Shimoda #include <linux/pm_runtime.h>
19*7c7356baSYoshihiro Shimoda 
20*7c7356baSYoshihiro Shimoda #define USB30_CLKSET0		0x034
21*7c7356baSYoshihiro Shimoda #define USB30_CLKSET1		0x036
22*7c7356baSYoshihiro Shimoda #define USB30_SSC_SET		0x038
23*7c7356baSYoshihiro Shimoda #define USB30_PHY_ENABLE	0x060
24*7c7356baSYoshihiro Shimoda #define USB30_VBUS_EN		0x064
25*7c7356baSYoshihiro Shimoda 
26*7c7356baSYoshihiro Shimoda /* USB30_CLKSET0 */
27*7c7356baSYoshihiro Shimoda #define CLKSET0_PRIVATE			0x05c0
28*7c7356baSYoshihiro Shimoda #define CLKSET0_USB30_FSEL_USB_EXTAL	0x0002
29*7c7356baSYoshihiro Shimoda 
30*7c7356baSYoshihiro Shimoda /* USB30_CLKSET1 */
31*7c7356baSYoshihiro Shimoda #define CLKSET1_USB30_PLL_MULTI_SHIFT		6
32*7c7356baSYoshihiro Shimoda #define CLKSET1_USB30_PLL_MULTI_USB_EXTAL	(0x64 << \
33*7c7356baSYoshihiro Shimoda 						 CLKSET1_USB30_PLL_MULTI_SHIFT)
34*7c7356baSYoshihiro Shimoda #define CLKSET1_PHYRESET	BIT(4)	/* 1: reset */
35*7c7356baSYoshihiro Shimoda #define CLKSET1_REF_CLKDIV	BIT(3)	/* 1: USB_EXTAL */
36*7c7356baSYoshihiro Shimoda #define CLKSET1_PRIVATE_2_1	BIT(1)	/* Write B'01 */
37*7c7356baSYoshihiro Shimoda #define CLKSET1_REF_CLK_SEL	BIT(0)	/* 1: USB3S0_CLK_P */
38*7c7356baSYoshihiro Shimoda 
39*7c7356baSYoshihiro Shimoda /* USB30_SSC_SET */
40*7c7356baSYoshihiro Shimoda #define SSC_SET_SSC_EN		BIT(12)
41*7c7356baSYoshihiro Shimoda #define SSC_SET_RANGE_SHIFT	9
42*7c7356baSYoshihiro Shimoda #define SSC_SET_RANGE_4980	(0x0 << SSC_SET_RANGE_SHIFT)
43*7c7356baSYoshihiro Shimoda #define SSC_SET_RANGE_4492	(0x1 << SSC_SET_RANGE_SHIFT)
44*7c7356baSYoshihiro Shimoda #define SSC_SET_RANGE_4003	(0x2 << SSC_SET_RANGE_SHIFT)
45*7c7356baSYoshihiro Shimoda 
46*7c7356baSYoshihiro Shimoda /* USB30_PHY_ENABLE */
47*7c7356baSYoshihiro Shimoda #define PHY_ENABLE_RESET_EN	BIT(4)
48*7c7356baSYoshihiro Shimoda 
49*7c7356baSYoshihiro Shimoda /* USB30_VBUS_EN */
50*7c7356baSYoshihiro Shimoda #define VBUS_EN_VBUS_EN		BIT(1)
51*7c7356baSYoshihiro Shimoda 
52*7c7356baSYoshihiro Shimoda struct rcar_gen3_usb3 {
53*7c7356baSYoshihiro Shimoda 	void __iomem *base;
54*7c7356baSYoshihiro Shimoda 	struct phy *phy;
55*7c7356baSYoshihiro Shimoda 	u32 ssc_range;
56*7c7356baSYoshihiro Shimoda 	bool usb3s_clk;
57*7c7356baSYoshihiro Shimoda 	bool usb_extal;
58*7c7356baSYoshihiro Shimoda };
59*7c7356baSYoshihiro Shimoda 
60*7c7356baSYoshihiro Shimoda static void write_clkset1_for_usb_extal(struct rcar_gen3_usb3 *r, bool reset)
61*7c7356baSYoshihiro Shimoda {
62*7c7356baSYoshihiro Shimoda 	u16 val = CLKSET1_USB30_PLL_MULTI_USB_EXTAL |
63*7c7356baSYoshihiro Shimoda 		  CLKSET1_REF_CLKDIV | CLKSET1_PRIVATE_2_1;
64*7c7356baSYoshihiro Shimoda 
65*7c7356baSYoshihiro Shimoda 	if (reset)
66*7c7356baSYoshihiro Shimoda 		val |= CLKSET1_PHYRESET;
67*7c7356baSYoshihiro Shimoda 
68*7c7356baSYoshihiro Shimoda 	writew(val, r->base + USB30_CLKSET1);
69*7c7356baSYoshihiro Shimoda }
70*7c7356baSYoshihiro Shimoda 
71*7c7356baSYoshihiro Shimoda static void rcar_gen3_phy_usb3_enable_ssc(struct rcar_gen3_usb3 *r)
72*7c7356baSYoshihiro Shimoda {
73*7c7356baSYoshihiro Shimoda 	u16 val = SSC_SET_SSC_EN;
74*7c7356baSYoshihiro Shimoda 
75*7c7356baSYoshihiro Shimoda 	switch (r->ssc_range) {
76*7c7356baSYoshihiro Shimoda 	case 4980:
77*7c7356baSYoshihiro Shimoda 		val |= SSC_SET_RANGE_4980;
78*7c7356baSYoshihiro Shimoda 		break;
79*7c7356baSYoshihiro Shimoda 	case 4492:
80*7c7356baSYoshihiro Shimoda 		val |= SSC_SET_RANGE_4492;
81*7c7356baSYoshihiro Shimoda 		break;
82*7c7356baSYoshihiro Shimoda 	case 4003:
83*7c7356baSYoshihiro Shimoda 		val |= SSC_SET_RANGE_4003;
84*7c7356baSYoshihiro Shimoda 		break;
85*7c7356baSYoshihiro Shimoda 	default:
86*7c7356baSYoshihiro Shimoda 		dev_err(&r->phy->dev, "%s: unsupported range (%x)\n", __func__,
87*7c7356baSYoshihiro Shimoda 			r->ssc_range);
88*7c7356baSYoshihiro Shimoda 		return;
89*7c7356baSYoshihiro Shimoda 	}
90*7c7356baSYoshihiro Shimoda 
91*7c7356baSYoshihiro Shimoda 	writew(val, r->base + USB30_SSC_SET);
92*7c7356baSYoshihiro Shimoda }
93*7c7356baSYoshihiro Shimoda 
94*7c7356baSYoshihiro Shimoda static void rcar_gen3_phy_usb3_select_usb_extal(struct rcar_gen3_usb3 *r)
95*7c7356baSYoshihiro Shimoda {
96*7c7356baSYoshihiro Shimoda 	write_clkset1_for_usb_extal(r, false);
97*7c7356baSYoshihiro Shimoda 	if (r->ssc_range)
98*7c7356baSYoshihiro Shimoda 		rcar_gen3_phy_usb3_enable_ssc(r);
99*7c7356baSYoshihiro Shimoda 	writew(CLKSET0_PRIVATE | CLKSET0_USB30_FSEL_USB_EXTAL,
100*7c7356baSYoshihiro Shimoda 	       r->base + USB30_CLKSET0);
101*7c7356baSYoshihiro Shimoda 	writew(PHY_ENABLE_RESET_EN, r->base + USB30_PHY_ENABLE);
102*7c7356baSYoshihiro Shimoda 	write_clkset1_for_usb_extal(r, true);
103*7c7356baSYoshihiro Shimoda 	usleep_range(10, 20);
104*7c7356baSYoshihiro Shimoda 	write_clkset1_for_usb_extal(r, false);
105*7c7356baSYoshihiro Shimoda }
106*7c7356baSYoshihiro Shimoda 
107*7c7356baSYoshihiro Shimoda static int rcar_gen3_phy_usb3_init(struct phy *p)
108*7c7356baSYoshihiro Shimoda {
109*7c7356baSYoshihiro Shimoda 	struct rcar_gen3_usb3 *r = phy_get_drvdata(p);
110*7c7356baSYoshihiro Shimoda 
111*7c7356baSYoshihiro Shimoda 	dev_vdbg(&r->phy->dev, "%s: enter (%d, %d, %d)\n", __func__,
112*7c7356baSYoshihiro Shimoda 		 r->usb3s_clk, r->usb_extal, r->ssc_range);
113*7c7356baSYoshihiro Shimoda 
114*7c7356baSYoshihiro Shimoda 	if (!r->usb3s_clk && r->usb_extal)
115*7c7356baSYoshihiro Shimoda 		rcar_gen3_phy_usb3_select_usb_extal(r);
116*7c7356baSYoshihiro Shimoda 
117*7c7356baSYoshihiro Shimoda 	/* Enables VBUS detection anyway */
118*7c7356baSYoshihiro Shimoda 	writew(VBUS_EN_VBUS_EN, r->base + USB30_VBUS_EN);
119*7c7356baSYoshihiro Shimoda 
120*7c7356baSYoshihiro Shimoda 	return 0;
121*7c7356baSYoshihiro Shimoda }
122*7c7356baSYoshihiro Shimoda 
123*7c7356baSYoshihiro Shimoda static const struct phy_ops rcar_gen3_phy_usb3_ops = {
124*7c7356baSYoshihiro Shimoda 	.init		= rcar_gen3_phy_usb3_init,
125*7c7356baSYoshihiro Shimoda 	.owner		= THIS_MODULE,
126*7c7356baSYoshihiro Shimoda };
127*7c7356baSYoshihiro Shimoda 
128*7c7356baSYoshihiro Shimoda static const struct of_device_id rcar_gen3_phy_usb3_match_table[] = {
129*7c7356baSYoshihiro Shimoda 	{ .compatible = "renesas,rcar-gen3-usb3-phy" },
130*7c7356baSYoshihiro Shimoda 	{ }
131*7c7356baSYoshihiro Shimoda };
132*7c7356baSYoshihiro Shimoda MODULE_DEVICE_TABLE(of, rcar_gen3_phy_usb3_match_table);
133*7c7356baSYoshihiro Shimoda 
134*7c7356baSYoshihiro Shimoda static int rcar_gen3_phy_usb3_probe(struct platform_device *pdev)
135*7c7356baSYoshihiro Shimoda {
136*7c7356baSYoshihiro Shimoda 	struct device *dev = &pdev->dev;
137*7c7356baSYoshihiro Shimoda 	struct rcar_gen3_usb3 *r;
138*7c7356baSYoshihiro Shimoda 	struct phy_provider *provider;
139*7c7356baSYoshihiro Shimoda 	struct resource *res;
140*7c7356baSYoshihiro Shimoda 	int ret = 0;
141*7c7356baSYoshihiro Shimoda 	struct clk *clk;
142*7c7356baSYoshihiro Shimoda 
143*7c7356baSYoshihiro Shimoda 	if (!dev->of_node) {
144*7c7356baSYoshihiro Shimoda 		dev_err(dev, "This driver needs device tree\n");
145*7c7356baSYoshihiro Shimoda 		return -EINVAL;
146*7c7356baSYoshihiro Shimoda 	}
147*7c7356baSYoshihiro Shimoda 
148*7c7356baSYoshihiro Shimoda 	r = devm_kzalloc(dev, sizeof(*r), GFP_KERNEL);
149*7c7356baSYoshihiro Shimoda 	if (!r)
150*7c7356baSYoshihiro Shimoda 		return -ENOMEM;
151*7c7356baSYoshihiro Shimoda 
152*7c7356baSYoshihiro Shimoda 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
153*7c7356baSYoshihiro Shimoda 	r->base = devm_ioremap_resource(dev, res);
154*7c7356baSYoshihiro Shimoda 	if (IS_ERR(r->base))
155*7c7356baSYoshihiro Shimoda 		return PTR_ERR(r->base);
156*7c7356baSYoshihiro Shimoda 
157*7c7356baSYoshihiro Shimoda 	clk = devm_clk_get(dev, "usb3s_clk");
158*7c7356baSYoshihiro Shimoda 	if (!IS_ERR(clk) && !clk_prepare_enable(clk)) {
159*7c7356baSYoshihiro Shimoda 		r->usb3s_clk = !!clk_get_rate(clk);
160*7c7356baSYoshihiro Shimoda 		clk_disable_unprepare(clk);
161*7c7356baSYoshihiro Shimoda 	}
162*7c7356baSYoshihiro Shimoda 	clk = devm_clk_get(dev, "usb_extal");
163*7c7356baSYoshihiro Shimoda 	if (!IS_ERR(clk) && !clk_prepare_enable(clk)) {
164*7c7356baSYoshihiro Shimoda 		r->usb_extal = !!clk_get_rate(clk);
165*7c7356baSYoshihiro Shimoda 		clk_disable_unprepare(clk);
166*7c7356baSYoshihiro Shimoda 	}
167*7c7356baSYoshihiro Shimoda 
168*7c7356baSYoshihiro Shimoda 	if (!r->usb3s_clk && !r->usb_extal) {
169*7c7356baSYoshihiro Shimoda 		dev_err(dev, "This driver needs usb3s_clk and/or usb_extal\n");
170*7c7356baSYoshihiro Shimoda 		ret = -EINVAL;
171*7c7356baSYoshihiro Shimoda 		goto error;
172*7c7356baSYoshihiro Shimoda 	}
173*7c7356baSYoshihiro Shimoda 
174*7c7356baSYoshihiro Shimoda 	/*
175*7c7356baSYoshihiro Shimoda 	 * devm_phy_create() will call pm_runtime_enable(&phy->dev);
176*7c7356baSYoshihiro Shimoda 	 * And then, phy-core will manage runtime pm for this device.
177*7c7356baSYoshihiro Shimoda 	 */
178*7c7356baSYoshihiro Shimoda 	pm_runtime_enable(dev);
179*7c7356baSYoshihiro Shimoda 
180*7c7356baSYoshihiro Shimoda 	r->phy = devm_phy_create(dev, NULL, &rcar_gen3_phy_usb3_ops);
181*7c7356baSYoshihiro Shimoda 	if (IS_ERR(r->phy)) {
182*7c7356baSYoshihiro Shimoda 		dev_err(dev, "Failed to create USB3 PHY\n");
183*7c7356baSYoshihiro Shimoda 		ret = PTR_ERR(r->phy);
184*7c7356baSYoshihiro Shimoda 		goto error;
185*7c7356baSYoshihiro Shimoda 	}
186*7c7356baSYoshihiro Shimoda 
187*7c7356baSYoshihiro Shimoda 	of_property_read_u32(dev->of_node, "renesas,ssc-range", &r->ssc_range);
188*7c7356baSYoshihiro Shimoda 
189*7c7356baSYoshihiro Shimoda 	platform_set_drvdata(pdev, r);
190*7c7356baSYoshihiro Shimoda 	phy_set_drvdata(r->phy, r);
191*7c7356baSYoshihiro Shimoda 
192*7c7356baSYoshihiro Shimoda 	provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
193*7c7356baSYoshihiro Shimoda 	if (IS_ERR(provider)) {
194*7c7356baSYoshihiro Shimoda 		dev_err(dev, "Failed to register PHY provider\n");
195*7c7356baSYoshihiro Shimoda 		ret = PTR_ERR(provider);
196*7c7356baSYoshihiro Shimoda 		goto error;
197*7c7356baSYoshihiro Shimoda 	}
198*7c7356baSYoshihiro Shimoda 
199*7c7356baSYoshihiro Shimoda 	return 0;
200*7c7356baSYoshihiro Shimoda 
201*7c7356baSYoshihiro Shimoda error:
202*7c7356baSYoshihiro Shimoda 	pm_runtime_disable(dev);
203*7c7356baSYoshihiro Shimoda 
204*7c7356baSYoshihiro Shimoda 	return ret;
205*7c7356baSYoshihiro Shimoda }
206*7c7356baSYoshihiro Shimoda 
207*7c7356baSYoshihiro Shimoda static int rcar_gen3_phy_usb3_remove(struct platform_device *pdev)
208*7c7356baSYoshihiro Shimoda {
209*7c7356baSYoshihiro Shimoda 	pm_runtime_disable(&pdev->dev);
210*7c7356baSYoshihiro Shimoda 
211*7c7356baSYoshihiro Shimoda 	return 0;
212*7c7356baSYoshihiro Shimoda };
213*7c7356baSYoshihiro Shimoda 
214*7c7356baSYoshihiro Shimoda static struct platform_driver rcar_gen3_phy_usb3_driver = {
215*7c7356baSYoshihiro Shimoda 	.driver = {
216*7c7356baSYoshihiro Shimoda 		.name		= "phy_rcar_gen3_usb3",
217*7c7356baSYoshihiro Shimoda 		.of_match_table	= rcar_gen3_phy_usb3_match_table,
218*7c7356baSYoshihiro Shimoda 	},
219*7c7356baSYoshihiro Shimoda 	.probe	= rcar_gen3_phy_usb3_probe,
220*7c7356baSYoshihiro Shimoda 	.remove = rcar_gen3_phy_usb3_remove,
221*7c7356baSYoshihiro Shimoda };
222*7c7356baSYoshihiro Shimoda module_platform_driver(rcar_gen3_phy_usb3_driver);
223*7c7356baSYoshihiro Shimoda 
224*7c7356baSYoshihiro Shimoda MODULE_LICENSE("GPL v2");
225*7c7356baSYoshihiro Shimoda MODULE_DESCRIPTION("Renesas R-Car Gen3 USB 3.0 PHY");
226*7c7356baSYoshihiro Shimoda MODULE_AUTHOR("Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>");
227