xref: /linux/drivers/phy/socionext/phy-uniphier-usb2.c (revision c339d3e0fb100465d644ccf84590e6f5e5ad80b9)
1*c339d3e0SKunihiko Hayashi // SPDX-License-Identifier: GPL-2.0
2*c339d3e0SKunihiko Hayashi /*
3*c339d3e0SKunihiko Hayashi  * phy-uniphier-usb2.c - PHY driver for UniPhier USB2 controller
4*c339d3e0SKunihiko Hayashi  * Copyright 2015-2018 Socionext Inc.
5*c339d3e0SKunihiko Hayashi  * Author:
6*c339d3e0SKunihiko Hayashi  *      Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
7*c339d3e0SKunihiko Hayashi  */
8*c339d3e0SKunihiko Hayashi 
9*c339d3e0SKunihiko Hayashi #include <linux/mfd/syscon.h>
10*c339d3e0SKunihiko Hayashi #include <linux/module.h>
11*c339d3e0SKunihiko Hayashi #include <linux/of.h>
12*c339d3e0SKunihiko Hayashi #include <linux/of_platform.h>
13*c339d3e0SKunihiko Hayashi #include <linux/phy/phy.h>
14*c339d3e0SKunihiko Hayashi #include <linux/platform_device.h>
15*c339d3e0SKunihiko Hayashi #include <linux/regmap.h>
16*c339d3e0SKunihiko Hayashi #include <linux/regulator/consumer.h>
17*c339d3e0SKunihiko Hayashi 
18*c339d3e0SKunihiko Hayashi #define SG_USBPHY1CTRL		0x500
19*c339d3e0SKunihiko Hayashi #define SG_USBPHY1CTRL2		0x504
20*c339d3e0SKunihiko Hayashi #define SG_USBPHY2CTRL		0x508
21*c339d3e0SKunihiko Hayashi #define SG_USBPHY2CTRL2		0x50c	/* LD11 */
22*c339d3e0SKunihiko Hayashi #define SG_USBPHY12PLL		0x50c	/* Pro4 */
23*c339d3e0SKunihiko Hayashi #define SG_USBPHY3CTRL		0x510
24*c339d3e0SKunihiko Hayashi #define SG_USBPHY3CTRL2		0x514
25*c339d3e0SKunihiko Hayashi #define SG_USBPHY4CTRL		0x518	/* Pro4 */
26*c339d3e0SKunihiko Hayashi #define SG_USBPHY4CTRL2		0x51c	/* Pro4 */
27*c339d3e0SKunihiko Hayashi #define SG_USBPHY34PLL		0x51c	/* Pro4 */
28*c339d3e0SKunihiko Hayashi 
29*c339d3e0SKunihiko Hayashi struct uniphier_u2phy_param {
30*c339d3e0SKunihiko Hayashi 	u32 offset;
31*c339d3e0SKunihiko Hayashi 	u32 value;
32*c339d3e0SKunihiko Hayashi };
33*c339d3e0SKunihiko Hayashi 
34*c339d3e0SKunihiko Hayashi struct uniphier_u2phy_soc_data {
35*c339d3e0SKunihiko Hayashi 	struct uniphier_u2phy_param config0;
36*c339d3e0SKunihiko Hayashi 	struct uniphier_u2phy_param config1;
37*c339d3e0SKunihiko Hayashi };
38*c339d3e0SKunihiko Hayashi 
39*c339d3e0SKunihiko Hayashi struct uniphier_u2phy_priv {
40*c339d3e0SKunihiko Hayashi 	struct regmap *regmap;
41*c339d3e0SKunihiko Hayashi 	struct phy *phy;
42*c339d3e0SKunihiko Hayashi 	struct regulator *vbus;
43*c339d3e0SKunihiko Hayashi 	const struct uniphier_u2phy_soc_data *data;
44*c339d3e0SKunihiko Hayashi 	struct uniphier_u2phy_priv *next;
45*c339d3e0SKunihiko Hayashi };
46*c339d3e0SKunihiko Hayashi 
47*c339d3e0SKunihiko Hayashi static int uniphier_u2phy_power_on(struct phy *phy)
48*c339d3e0SKunihiko Hayashi {
49*c339d3e0SKunihiko Hayashi 	struct uniphier_u2phy_priv *priv = phy_get_drvdata(phy);
50*c339d3e0SKunihiko Hayashi 	int ret = 0;
51*c339d3e0SKunihiko Hayashi 
52*c339d3e0SKunihiko Hayashi 	if (priv->vbus)
53*c339d3e0SKunihiko Hayashi 		ret = regulator_enable(priv->vbus);
54*c339d3e0SKunihiko Hayashi 
55*c339d3e0SKunihiko Hayashi 	return ret;
56*c339d3e0SKunihiko Hayashi }
57*c339d3e0SKunihiko Hayashi 
58*c339d3e0SKunihiko Hayashi static int uniphier_u2phy_power_off(struct phy *phy)
59*c339d3e0SKunihiko Hayashi {
60*c339d3e0SKunihiko Hayashi 	struct uniphier_u2phy_priv *priv = phy_get_drvdata(phy);
61*c339d3e0SKunihiko Hayashi 
62*c339d3e0SKunihiko Hayashi 	if (priv->vbus)
63*c339d3e0SKunihiko Hayashi 		regulator_disable(priv->vbus);
64*c339d3e0SKunihiko Hayashi 
65*c339d3e0SKunihiko Hayashi 	return 0;
66*c339d3e0SKunihiko Hayashi }
67*c339d3e0SKunihiko Hayashi 
68*c339d3e0SKunihiko Hayashi static int uniphier_u2phy_init(struct phy *phy)
69*c339d3e0SKunihiko Hayashi {
70*c339d3e0SKunihiko Hayashi 	struct uniphier_u2phy_priv *priv = phy_get_drvdata(phy);
71*c339d3e0SKunihiko Hayashi 
72*c339d3e0SKunihiko Hayashi 	if (!priv->data)
73*c339d3e0SKunihiko Hayashi 		return 0;
74*c339d3e0SKunihiko Hayashi 
75*c339d3e0SKunihiko Hayashi 	regmap_write(priv->regmap, priv->data->config0.offset,
76*c339d3e0SKunihiko Hayashi 		     priv->data->config0.value);
77*c339d3e0SKunihiko Hayashi 	regmap_write(priv->regmap, priv->data->config1.offset,
78*c339d3e0SKunihiko Hayashi 		     priv->data->config1.value);
79*c339d3e0SKunihiko Hayashi 
80*c339d3e0SKunihiko Hayashi 	return 0;
81*c339d3e0SKunihiko Hayashi }
82*c339d3e0SKunihiko Hayashi 
83*c339d3e0SKunihiko Hayashi static struct phy *uniphier_u2phy_xlate(struct device *dev,
84*c339d3e0SKunihiko Hayashi 					struct of_phandle_args *args)
85*c339d3e0SKunihiko Hayashi {
86*c339d3e0SKunihiko Hayashi 	struct uniphier_u2phy_priv *priv = dev_get_drvdata(dev);
87*c339d3e0SKunihiko Hayashi 
88*c339d3e0SKunihiko Hayashi 	while (priv && args->np != priv->phy->dev.of_node)
89*c339d3e0SKunihiko Hayashi 		priv = priv->next;
90*c339d3e0SKunihiko Hayashi 
91*c339d3e0SKunihiko Hayashi 	if (!priv) {
92*c339d3e0SKunihiko Hayashi 		dev_err(dev, "Failed to find appropriate phy\n");
93*c339d3e0SKunihiko Hayashi 		return ERR_PTR(-EINVAL);
94*c339d3e0SKunihiko Hayashi 	}
95*c339d3e0SKunihiko Hayashi 
96*c339d3e0SKunihiko Hayashi 	return priv->phy;
97*c339d3e0SKunihiko Hayashi }
98*c339d3e0SKunihiko Hayashi 
99*c339d3e0SKunihiko Hayashi static const struct phy_ops uniphier_u2phy_ops = {
100*c339d3e0SKunihiko Hayashi 	.init      = uniphier_u2phy_init,
101*c339d3e0SKunihiko Hayashi 	.power_on  = uniphier_u2phy_power_on,
102*c339d3e0SKunihiko Hayashi 	.power_off = uniphier_u2phy_power_off,
103*c339d3e0SKunihiko Hayashi 	.owner = THIS_MODULE,
104*c339d3e0SKunihiko Hayashi };
105*c339d3e0SKunihiko Hayashi 
106*c339d3e0SKunihiko Hayashi static int uniphier_u2phy_probe(struct platform_device *pdev)
107*c339d3e0SKunihiko Hayashi {
108*c339d3e0SKunihiko Hayashi 	struct device *dev = &pdev->dev;
109*c339d3e0SKunihiko Hayashi 	struct device_node *parent, *child;
110*c339d3e0SKunihiko Hayashi 	struct uniphier_u2phy_priv *priv = NULL, *next = NULL;
111*c339d3e0SKunihiko Hayashi 	struct phy_provider *phy_provider;
112*c339d3e0SKunihiko Hayashi 	struct regmap *regmap;
113*c339d3e0SKunihiko Hayashi 	const struct uniphier_u2phy_soc_data *data;
114*c339d3e0SKunihiko Hayashi 	int ret, data_idx, ndatas;
115*c339d3e0SKunihiko Hayashi 
116*c339d3e0SKunihiko Hayashi 	data = of_device_get_match_data(dev);
117*c339d3e0SKunihiko Hayashi 	if (WARN_ON(!data))
118*c339d3e0SKunihiko Hayashi 		return -EINVAL;
119*c339d3e0SKunihiko Hayashi 
120*c339d3e0SKunihiko Hayashi 	/* get number of data */
121*c339d3e0SKunihiko Hayashi 	for (ndatas = 0; data[ndatas].config0.offset; ndatas++)
122*c339d3e0SKunihiko Hayashi 		;
123*c339d3e0SKunihiko Hayashi 
124*c339d3e0SKunihiko Hayashi 	parent = of_get_parent(dev->of_node);
125*c339d3e0SKunihiko Hayashi 	regmap = syscon_node_to_regmap(parent);
126*c339d3e0SKunihiko Hayashi 	of_node_put(parent);
127*c339d3e0SKunihiko Hayashi 	if (IS_ERR(regmap)) {
128*c339d3e0SKunihiko Hayashi 		dev_err(dev, "Failed to get regmap\n");
129*c339d3e0SKunihiko Hayashi 		return PTR_ERR(regmap);
130*c339d3e0SKunihiko Hayashi 	}
131*c339d3e0SKunihiko Hayashi 
132*c339d3e0SKunihiko Hayashi 	for_each_child_of_node(dev->of_node, child) {
133*c339d3e0SKunihiko Hayashi 		priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
134*c339d3e0SKunihiko Hayashi 		if (!priv) {
135*c339d3e0SKunihiko Hayashi 			ret = -ENOMEM;
136*c339d3e0SKunihiko Hayashi 			goto out_put_child;
137*c339d3e0SKunihiko Hayashi 		}
138*c339d3e0SKunihiko Hayashi 		priv->regmap = regmap;
139*c339d3e0SKunihiko Hayashi 
140*c339d3e0SKunihiko Hayashi 		priv->vbus = devm_regulator_get_optional(dev, "vbus");
141*c339d3e0SKunihiko Hayashi 		if (IS_ERR(priv->vbus)) {
142*c339d3e0SKunihiko Hayashi 			if (PTR_ERR(priv->vbus) == -EPROBE_DEFER) {
143*c339d3e0SKunihiko Hayashi 				ret = PTR_ERR(priv->vbus);
144*c339d3e0SKunihiko Hayashi 				goto out_put_child;
145*c339d3e0SKunihiko Hayashi 			}
146*c339d3e0SKunihiko Hayashi 			priv->vbus = NULL;
147*c339d3e0SKunihiko Hayashi 		}
148*c339d3e0SKunihiko Hayashi 
149*c339d3e0SKunihiko Hayashi 		priv->phy = devm_phy_create(dev, child, &uniphier_u2phy_ops);
150*c339d3e0SKunihiko Hayashi 		if (IS_ERR(priv->phy)) {
151*c339d3e0SKunihiko Hayashi 			dev_err(dev, "Failed to create phy\n");
152*c339d3e0SKunihiko Hayashi 			ret = PTR_ERR(priv->phy);
153*c339d3e0SKunihiko Hayashi 			goto out_put_child;
154*c339d3e0SKunihiko Hayashi 		}
155*c339d3e0SKunihiko Hayashi 
156*c339d3e0SKunihiko Hayashi 		ret = of_property_read_u32(child, "reg", &data_idx);
157*c339d3e0SKunihiko Hayashi 		if (ret) {
158*c339d3e0SKunihiko Hayashi 			dev_err(dev, "Failed to get reg property\n");
159*c339d3e0SKunihiko Hayashi 			goto out_put_child;
160*c339d3e0SKunihiko Hayashi 		}
161*c339d3e0SKunihiko Hayashi 
162*c339d3e0SKunihiko Hayashi 		if (data_idx < ndatas)
163*c339d3e0SKunihiko Hayashi 			priv->data = &data[data_idx];
164*c339d3e0SKunihiko Hayashi 		else
165*c339d3e0SKunihiko Hayashi 			dev_warn(dev, "No phy configuration: %s\n",
166*c339d3e0SKunihiko Hayashi 				 child->full_name);
167*c339d3e0SKunihiko Hayashi 
168*c339d3e0SKunihiko Hayashi 		phy_set_drvdata(priv->phy, priv);
169*c339d3e0SKunihiko Hayashi 		priv->next = next;
170*c339d3e0SKunihiko Hayashi 		next = priv;
171*c339d3e0SKunihiko Hayashi 	}
172*c339d3e0SKunihiko Hayashi 
173*c339d3e0SKunihiko Hayashi 	dev_set_drvdata(dev, priv);
174*c339d3e0SKunihiko Hayashi 	phy_provider = devm_of_phy_provider_register(dev,
175*c339d3e0SKunihiko Hayashi 						     uniphier_u2phy_xlate);
176*c339d3e0SKunihiko Hayashi 	return PTR_ERR_OR_ZERO(phy_provider);
177*c339d3e0SKunihiko Hayashi 
178*c339d3e0SKunihiko Hayashi out_put_child:
179*c339d3e0SKunihiko Hayashi 	of_node_put(child);
180*c339d3e0SKunihiko Hayashi 
181*c339d3e0SKunihiko Hayashi 	return ret;
182*c339d3e0SKunihiko Hayashi }
183*c339d3e0SKunihiko Hayashi 
184*c339d3e0SKunihiko Hayashi static const struct uniphier_u2phy_soc_data uniphier_pro4_data[] = {
185*c339d3e0SKunihiko Hayashi 	{
186*c339d3e0SKunihiko Hayashi 		.config0 = { SG_USBPHY1CTRL, 0x05142400 },
187*c339d3e0SKunihiko Hayashi 		.config1 = { SG_USBPHY12PLL, 0x00010010 },
188*c339d3e0SKunihiko Hayashi 	},
189*c339d3e0SKunihiko Hayashi 	{
190*c339d3e0SKunihiko Hayashi 		.config0 = { SG_USBPHY2CTRL, 0x05142400 },
191*c339d3e0SKunihiko Hayashi 		.config1 = { SG_USBPHY12PLL, 0x00010010 },
192*c339d3e0SKunihiko Hayashi 	},
193*c339d3e0SKunihiko Hayashi 	{
194*c339d3e0SKunihiko Hayashi 		.config0 = { SG_USBPHY3CTRL, 0x05142400 },
195*c339d3e0SKunihiko Hayashi 		.config1 = { SG_USBPHY34PLL, 0x00010010 },
196*c339d3e0SKunihiko Hayashi 	},
197*c339d3e0SKunihiko Hayashi 	{
198*c339d3e0SKunihiko Hayashi 		.config0 = { SG_USBPHY4CTRL, 0x05142400 },
199*c339d3e0SKunihiko Hayashi 		.config1 = { SG_USBPHY34PLL, 0x00010010 },
200*c339d3e0SKunihiko Hayashi 	},
201*c339d3e0SKunihiko Hayashi 	{ /* sentinel */ }
202*c339d3e0SKunihiko Hayashi };
203*c339d3e0SKunihiko Hayashi 
204*c339d3e0SKunihiko Hayashi static const struct uniphier_u2phy_soc_data uniphier_ld11_data[] = {
205*c339d3e0SKunihiko Hayashi 	{
206*c339d3e0SKunihiko Hayashi 		.config0 = { SG_USBPHY1CTRL,  0x82280000 },
207*c339d3e0SKunihiko Hayashi 		.config1 = { SG_USBPHY1CTRL2, 0x00000106 },
208*c339d3e0SKunihiko Hayashi 	},
209*c339d3e0SKunihiko Hayashi 	{
210*c339d3e0SKunihiko Hayashi 		.config0 = { SG_USBPHY2CTRL,  0x82280000 },
211*c339d3e0SKunihiko Hayashi 		.config1 = { SG_USBPHY2CTRL2, 0x00000106 },
212*c339d3e0SKunihiko Hayashi 	},
213*c339d3e0SKunihiko Hayashi 	{
214*c339d3e0SKunihiko Hayashi 		.config0 = { SG_USBPHY3CTRL,  0x82280000 },
215*c339d3e0SKunihiko Hayashi 		.config1 = { SG_USBPHY3CTRL2, 0x00000106 },
216*c339d3e0SKunihiko Hayashi 	},
217*c339d3e0SKunihiko Hayashi 	{ /* sentinel */ }
218*c339d3e0SKunihiko Hayashi };
219*c339d3e0SKunihiko Hayashi 
220*c339d3e0SKunihiko Hayashi static const struct of_device_id uniphier_u2phy_match[] = {
221*c339d3e0SKunihiko Hayashi 	{
222*c339d3e0SKunihiko Hayashi 		.compatible = "socionext,uniphier-pro4-usb2-phy",
223*c339d3e0SKunihiko Hayashi 		.data = &uniphier_pro4_data,
224*c339d3e0SKunihiko Hayashi 	},
225*c339d3e0SKunihiko Hayashi 	{
226*c339d3e0SKunihiko Hayashi 		.compatible = "socionext,uniphier-ld11-usb2-phy",
227*c339d3e0SKunihiko Hayashi 		.data = &uniphier_ld11_data,
228*c339d3e0SKunihiko Hayashi 	},
229*c339d3e0SKunihiko Hayashi 	{ /* sentinel */ }
230*c339d3e0SKunihiko Hayashi };
231*c339d3e0SKunihiko Hayashi MODULE_DEVICE_TABLE(of, uniphier_u2phy_match);
232*c339d3e0SKunihiko Hayashi 
233*c339d3e0SKunihiko Hayashi static struct platform_driver uniphier_u2phy_driver = {
234*c339d3e0SKunihiko Hayashi 	.probe = uniphier_u2phy_probe,
235*c339d3e0SKunihiko Hayashi 	.driver = {
236*c339d3e0SKunihiko Hayashi 		.name = "uniphier-usb2-phy",
237*c339d3e0SKunihiko Hayashi 		.of_match_table = uniphier_u2phy_match,
238*c339d3e0SKunihiko Hayashi 	},
239*c339d3e0SKunihiko Hayashi };
240*c339d3e0SKunihiko Hayashi module_platform_driver(uniphier_u2phy_driver);
241*c339d3e0SKunihiko Hayashi 
242*c339d3e0SKunihiko Hayashi MODULE_AUTHOR("Kunihiko Hayashi <hayashi.kunihiko@socionext.com>");
243*c339d3e0SKunihiko Hayashi MODULE_DESCRIPTION("UniPhier PHY driver for USB2 controller");
244*c339d3e0SKunihiko Hayashi MODULE_LICENSE("GPL v2");
245