1 // SPDX-License-Identifier: GPL-2.0
3 * phy-uniphier-usb3ss.c - SS-PHY driver for Socionext UniPhier USB3 controller
4 * Copyright 2015-2018 Socionext Inc.
6 * Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
8 * Motoya Tanigawa <tanigawa.motoya@socionext.com>
9 * Masami Hiramatsu <masami.hiramatsu@linaro.org>
12 #include <linux/bitfield.h>
13 #include <linux/bitops.h>
14 #include <linux/clk.h>
16 #include <linux/module.h>
18 #include <linux/of_platform.h>
19 #include <linux/phy/phy.h>
20 #include <linux/platform_device.h>
21 #include <linux/regulator/consumer.h>
22 #include <linux/reset.h>
24 #define SSPHY_TESTI 0x0
25 #define SSPHY_TESTO 0x4
26 #define TESTI_DAT_MASK GENMASK(13, 6)
27 #define TESTI_ADR_MASK GENMASK(5, 1)
28 #define TESTI_WR_EN BIT(0)
30 #define PHY_F(regno, msb, lsb) { (regno), (msb), (lsb) }
32 #define CDR_CPD_TRIM PHY_F(7, 3, 0) /* RxPLL charge pump current */
33 #define CDR_CPF_TRIM PHY_F(8, 3, 0) /* RxPLL charge pump current 2 */
34 #define TX_PLL_TRIM PHY_F(9, 3, 0) /* TxPLL charge pump current */
35 #define BGAP_TRIM PHY_F(11, 3, 0) /* Bandgap voltage */
36 #define CDR_TRIM PHY_F(13, 6, 5) /* Clock Data Recovery setting */
37 #define VCO_CTRL PHY_F(26, 7, 4) /* VCO control */
38 #define VCOPLL_CTRL PHY_F(27, 2, 0) /* TxPLL VCO tuning */
39 #define VCOPLL_CM PHY_F(28, 1, 0) /* TxPLL voltage */
41 #define MAX_PHY_PARAMS 7
43 struct uniphier_u3ssphy_param
{
52 struct uniphier_u3ssphy_priv
{
55 struct clk
*clk
, *clk_ext
, *clk_parent
, *clk_parent_gio
;
56 struct reset_control
*rst
, *rst_parent
, *rst_parent_gio
;
57 struct regulator
*vbus
;
58 const struct uniphier_u3ssphy_soc_data
*data
;
61 struct uniphier_u3ssphy_soc_data
{
64 const struct uniphier_u3ssphy_param param
[MAX_PHY_PARAMS
];
67 static void uniphier_u3ssphy_testio_write(struct uniphier_u3ssphy_priv
*priv
,
70 /* need to read TESTO twice after accessing TESTI */
71 writel(data
, priv
->base
+ SSPHY_TESTI
);
72 readl(priv
->base
+ SSPHY_TESTO
);
73 readl(priv
->base
+ SSPHY_TESTO
);
76 static void uniphier_u3ssphy_set_param(struct uniphier_u3ssphy_priv
*priv
,
77 const struct uniphier_u3ssphy_param
*p
)
80 u8 field_mask
= GENMASK(p
->field
.msb
, p
->field
.lsb
);
83 /* read previous data */
84 val
= FIELD_PREP(TESTI_DAT_MASK
, 1);
85 val
|= FIELD_PREP(TESTI_ADR_MASK
, p
->field
.reg_no
);
86 uniphier_u3ssphy_testio_write(priv
, val
);
87 val
= readl(priv
->base
+ SSPHY_TESTO
);
90 val
&= ~FIELD_PREP(TESTI_DAT_MASK
, field_mask
);
91 data
= field_mask
& (p
->value
<< p
->field
.lsb
);
92 val
= FIELD_PREP(TESTI_DAT_MASK
, data
);
93 val
|= FIELD_PREP(TESTI_ADR_MASK
, p
->field
.reg_no
);
94 uniphier_u3ssphy_testio_write(priv
, val
);
95 uniphier_u3ssphy_testio_write(priv
, val
| TESTI_WR_EN
);
96 uniphier_u3ssphy_testio_write(priv
, val
);
98 /* read current data as dummy */
99 val
= FIELD_PREP(TESTI_DAT_MASK
, 1);
100 val
|= FIELD_PREP(TESTI_ADR_MASK
, p
->field
.reg_no
);
101 uniphier_u3ssphy_testio_write(priv
, val
);
102 readl(priv
->base
+ SSPHY_TESTO
);
105 static int uniphier_u3ssphy_power_on(struct phy
*phy
)
107 struct uniphier_u3ssphy_priv
*priv
= phy_get_drvdata(phy
);
110 ret
= clk_prepare_enable(priv
->clk_ext
);
114 ret
= clk_prepare_enable(priv
->clk
);
116 goto out_clk_ext_disable
;
118 ret
= reset_control_deassert(priv
->rst
);
120 goto out_clk_disable
;
123 ret
= regulator_enable(priv
->vbus
);
131 reset_control_assert(priv
->rst
);
133 clk_disable_unprepare(priv
->clk
);
135 clk_disable_unprepare(priv
->clk_ext
);
140 static int uniphier_u3ssphy_power_off(struct phy
*phy
)
142 struct uniphier_u3ssphy_priv
*priv
= phy_get_drvdata(phy
);
145 regulator_disable(priv
->vbus
);
147 reset_control_assert(priv
->rst
);
148 clk_disable_unprepare(priv
->clk
);
149 clk_disable_unprepare(priv
->clk_ext
);
154 static int uniphier_u3ssphy_init(struct phy
*phy
)
156 struct uniphier_u3ssphy_priv
*priv
= phy_get_drvdata(phy
);
159 ret
= clk_prepare_enable(priv
->clk_parent
);
163 ret
= clk_prepare_enable(priv
->clk_parent_gio
);
165 goto out_clk_disable
;
167 ret
= reset_control_deassert(priv
->rst_parent
);
169 goto out_clk_gio_disable
;
171 ret
= reset_control_deassert(priv
->rst_parent_gio
);
175 if (priv
->data
->is_legacy
)
178 for (i
= 0; i
< priv
->data
->nparams
; i
++)
179 uniphier_u3ssphy_set_param(priv
, &priv
->data
->param
[i
]);
184 reset_control_assert(priv
->rst_parent
);
186 clk_disable_unprepare(priv
->clk_parent_gio
);
188 clk_disable_unprepare(priv
->clk_parent
);
193 static int uniphier_u3ssphy_exit(struct phy
*phy
)
195 struct uniphier_u3ssphy_priv
*priv
= phy_get_drvdata(phy
);
197 reset_control_assert(priv
->rst_parent_gio
);
198 reset_control_assert(priv
->rst_parent
);
199 clk_disable_unprepare(priv
->clk_parent_gio
);
200 clk_disable_unprepare(priv
->clk_parent
);
205 static const struct phy_ops uniphier_u3ssphy_ops
= {
206 .init
= uniphier_u3ssphy_init
,
207 .exit
= uniphier_u3ssphy_exit
,
208 .power_on
= uniphier_u3ssphy_power_on
,
209 .power_off
= uniphier_u3ssphy_power_off
,
210 .owner
= THIS_MODULE
,
213 static int uniphier_u3ssphy_probe(struct platform_device
*pdev
)
215 struct device
*dev
= &pdev
->dev
;
216 struct uniphier_u3ssphy_priv
*priv
;
217 struct phy_provider
*phy_provider
;
218 struct resource
*res
;
221 priv
= devm_kzalloc(dev
, sizeof(*priv
), GFP_KERNEL
);
226 priv
->data
= of_device_get_match_data(dev
);
227 if (WARN_ON(!priv
->data
||
228 priv
->data
->nparams
> MAX_PHY_PARAMS
))
231 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
232 priv
->base
= devm_ioremap_resource(dev
, res
);
233 if (IS_ERR(priv
->base
))
234 return PTR_ERR(priv
->base
);
236 if (!priv
->data
->is_legacy
) {
237 priv
->clk
= devm_clk_get(dev
, "phy");
238 if (IS_ERR(priv
->clk
))
239 return PTR_ERR(priv
->clk
);
241 priv
->clk_ext
= devm_clk_get_optional(dev
, "phy-ext");
242 if (IS_ERR(priv
->clk_ext
))
243 return PTR_ERR(priv
->clk_ext
);
245 priv
->rst
= devm_reset_control_get_shared(dev
, "phy");
246 if (IS_ERR(priv
->rst
))
247 return PTR_ERR(priv
->rst
);
249 priv
->clk_parent_gio
= devm_clk_get(dev
, "gio");
250 if (IS_ERR(priv
->clk_parent_gio
))
251 return PTR_ERR(priv
->clk_parent_gio
);
253 priv
->rst_parent_gio
=
254 devm_reset_control_get_shared(dev
, "gio");
255 if (IS_ERR(priv
->rst_parent_gio
))
256 return PTR_ERR(priv
->rst_parent_gio
);
259 priv
->clk_parent
= devm_clk_get(dev
, "link");
260 if (IS_ERR(priv
->clk_parent
))
261 return PTR_ERR(priv
->clk_parent
);
263 priv
->rst_parent
= devm_reset_control_get_shared(dev
, "link");
264 if (IS_ERR(priv
->rst_parent
))
265 return PTR_ERR(priv
->rst_parent
);
267 priv
->vbus
= devm_regulator_get_optional(dev
, "vbus");
268 if (IS_ERR(priv
->vbus
)) {
269 if (PTR_ERR(priv
->vbus
) == -EPROBE_DEFER
)
270 return PTR_ERR(priv
->vbus
);
274 phy
= devm_phy_create(dev
, dev
->of_node
, &uniphier_u3ssphy_ops
);
278 phy_set_drvdata(phy
, priv
);
279 phy_provider
= devm_of_phy_provider_register(dev
, of_phy_simple_xlate
);
281 return PTR_ERR_OR_ZERO(phy_provider
);
284 static const struct uniphier_u3ssphy_soc_data uniphier_pro4_data
= {
288 static const struct uniphier_u3ssphy_soc_data uniphier_pxs2_data
= {
292 { CDR_CPD_TRIM
, 10 },
302 static const struct uniphier_u3ssphy_soc_data uniphier_ld20_data
= {
312 static const struct of_device_id uniphier_u3ssphy_match
[] = {
314 .compatible
= "socionext,uniphier-pro4-usb3-ssphy",
315 .data
= &uniphier_pro4_data
,
318 .compatible
= "socionext,uniphier-pxs2-usb3-ssphy",
319 .data
= &uniphier_pxs2_data
,
322 .compatible
= "socionext,uniphier-ld20-usb3-ssphy",
323 .data
= &uniphier_ld20_data
,
326 .compatible
= "socionext,uniphier-pxs3-usb3-ssphy",
327 .data
= &uniphier_ld20_data
,
331 MODULE_DEVICE_TABLE(of
, uniphier_u3ssphy_match
);
333 static struct platform_driver uniphier_u3ssphy_driver
= {
334 .probe
= uniphier_u3ssphy_probe
,
336 .name
= "uniphier-usb3-ssphy",
337 .of_match_table
= uniphier_u3ssphy_match
,
341 module_platform_driver(uniphier_u3ssphy_driver
);
343 MODULE_AUTHOR("Kunihiko Hayashi <hayashi.kunihiko@socionext.com>");
344 MODULE_DESCRIPTION("UniPhier SS-PHY driver for USB3 controller");
345 MODULE_LICENSE("GPL v2");