1 // SPDX-License-Identifier: GPL-2.0
3 * phy-uniphier-usb3hs.c - HS-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>
17 #include <linux/nvmem-consumer.h>
19 #include <linux/of_platform.h>
20 #include <linux/phy/phy.h>
21 #include <linux/platform_device.h>
22 #include <linux/regulator/consumer.h>
23 #include <linux/reset.h>
24 #include <linux/slab.h>
26 #define HSPHY_CFG0 0x0
27 #define HSPHY_CFG0_HS_I_MASK GENMASK(31, 28)
28 #define HSPHY_CFG0_HSDISC_MASK GENMASK(27, 26)
29 #define HSPHY_CFG0_SWING_MASK GENMASK(17, 16)
30 #define HSPHY_CFG0_SEL_T_MASK GENMASK(15, 12)
31 #define HSPHY_CFG0_RTERM_MASK GENMASK(7, 6)
32 #define HSPHY_CFG0_TRIMMASK (HSPHY_CFG0_HS_I_MASK \
33 | HSPHY_CFG0_SEL_T_MASK \
34 | HSPHY_CFG0_RTERM_MASK)
36 #define HSPHY_CFG1 0x4
37 #define HSPHY_CFG1_DAT_EN BIT(29)
38 #define HSPHY_CFG1_ADR_EN BIT(28)
39 #define HSPHY_CFG1_ADR_MASK GENMASK(27, 16)
40 #define HSPHY_CFG1_DAT_MASK GENMASK(23, 16)
42 #define PHY_F(regno, msb, lsb) { (regno), (msb), (lsb) }
44 #define RX_CHK_SYNC PHY_F(0, 5, 5) /* RX sync mode */
45 #define RX_SYNC_SEL PHY_F(1, 1, 0) /* RX sync length */
46 #define LS_SLEW PHY_F(10, 6, 6) /* LS mode slew rate */
47 #define FS_LS_DRV PHY_F(10, 5, 5) /* FS/LS slew rate */
49 #define MAX_PHY_PARAMS 4
51 struct uniphier_u3hsphy_param
{
60 struct uniphier_u3hsphy_trim_param
{
66 #define trim_param_is_valid(p) ((p)->rterm || (p)->sel_t || (p)->hs_i)
68 struct uniphier_u3hsphy_priv
{
71 struct clk
*clk
, *clk_parent
, *clk_ext
, *clk_parent_gio
;
72 struct reset_control
*rst
, *rst_parent
, *rst_parent_gio
;
73 struct regulator
*vbus
;
74 const struct uniphier_u3hsphy_soc_data
*data
;
77 struct uniphier_u3hsphy_soc_data
{
80 const struct uniphier_u3hsphy_param param
[MAX_PHY_PARAMS
];
83 void (*trim_func
)(struct uniphier_u3hsphy_priv
*priv
, u32
*pconfig
,
84 struct uniphier_u3hsphy_trim_param
*pt
);
87 static void uniphier_u3hsphy_trim_ld20(struct uniphier_u3hsphy_priv
*priv
,
89 struct uniphier_u3hsphy_trim_param
*pt
)
91 *pconfig
&= ~HSPHY_CFG0_RTERM_MASK
;
92 *pconfig
|= FIELD_PREP(HSPHY_CFG0_RTERM_MASK
, pt
->rterm
);
94 *pconfig
&= ~HSPHY_CFG0_SEL_T_MASK
;
95 *pconfig
|= FIELD_PREP(HSPHY_CFG0_SEL_T_MASK
, pt
->sel_t
);
97 *pconfig
&= ~HSPHY_CFG0_HS_I_MASK
;
98 *pconfig
|= FIELD_PREP(HSPHY_CFG0_HS_I_MASK
, pt
->hs_i
);
101 static int uniphier_u3hsphy_get_nvparam(struct uniphier_u3hsphy_priv
*priv
,
102 const char *name
, unsigned int *val
)
104 struct nvmem_cell
*cell
;
107 cell
= devm_nvmem_cell_get(priv
->dev
, name
);
109 return PTR_ERR(cell
);
111 buf
= nvmem_cell_read(cell
, NULL
);
122 static int uniphier_u3hsphy_get_nvparams(struct uniphier_u3hsphy_priv
*priv
,
123 struct uniphier_u3hsphy_trim_param
*pt
)
127 ret
= uniphier_u3hsphy_get_nvparam(priv
, "rterm", &pt
->rterm
);
131 ret
= uniphier_u3hsphy_get_nvparam(priv
, "sel_t", &pt
->sel_t
);
135 ret
= uniphier_u3hsphy_get_nvparam(priv
, "hs_i", &pt
->hs_i
);
142 static int uniphier_u3hsphy_update_config(struct uniphier_u3hsphy_priv
*priv
,
145 struct uniphier_u3hsphy_trim_param trim
;
146 int ret
, trimmed
= 0;
148 if (priv
->data
->trim_func
) {
149 ret
= uniphier_u3hsphy_get_nvparams(priv
, &trim
);
150 if (ret
== -EPROBE_DEFER
)
154 * call trim_func only when trimming parameters that aren't
155 * all-zero can be acquired. All-zero parameters mean nothing
156 * has been written to nvmem.
158 if (!ret
&& trim_param_is_valid(&trim
)) {
159 priv
->data
->trim_func(priv
, pconfig
, &trim
);
162 dev_dbg(priv
->dev
, "can't get parameter from nvmem\n");
166 /* use default parameters without trimming values */
168 *pconfig
&= ~HSPHY_CFG0_HSDISC_MASK
;
169 *pconfig
|= FIELD_PREP(HSPHY_CFG0_HSDISC_MASK
, 3);
175 static void uniphier_u3hsphy_set_param(struct uniphier_u3hsphy_priv
*priv
,
176 const struct uniphier_u3hsphy_param
*p
)
179 u32 field_mask
= GENMASK(p
->field
.msb
, p
->field
.lsb
);
182 val
= readl(priv
->base
+ HSPHY_CFG1
);
183 val
&= ~HSPHY_CFG1_ADR_MASK
;
184 val
|= FIELD_PREP(HSPHY_CFG1_ADR_MASK
, p
->field
.reg_no
)
186 writel(val
, priv
->base
+ HSPHY_CFG1
);
188 val
= readl(priv
->base
+ HSPHY_CFG1
);
189 val
&= ~HSPHY_CFG1_ADR_EN
;
190 writel(val
, priv
->base
+ HSPHY_CFG1
);
192 val
= readl(priv
->base
+ HSPHY_CFG1
);
193 val
&= ~FIELD_PREP(HSPHY_CFG1_DAT_MASK
, field_mask
);
194 data
= field_mask
& (p
->value
<< p
->field
.lsb
);
195 val
|= FIELD_PREP(HSPHY_CFG1_DAT_MASK
, data
) | HSPHY_CFG1_DAT_EN
;
196 writel(val
, priv
->base
+ HSPHY_CFG1
);
198 val
= readl(priv
->base
+ HSPHY_CFG1
);
199 val
&= ~HSPHY_CFG1_DAT_EN
;
200 writel(val
, priv
->base
+ HSPHY_CFG1
);
203 static int uniphier_u3hsphy_power_on(struct phy
*phy
)
205 struct uniphier_u3hsphy_priv
*priv
= phy_get_drvdata(phy
);
208 ret
= clk_prepare_enable(priv
->clk_ext
);
212 ret
= clk_prepare_enable(priv
->clk
);
214 goto out_clk_ext_disable
;
216 ret
= reset_control_deassert(priv
->rst
);
218 goto out_clk_disable
;
221 ret
= regulator_enable(priv
->vbus
);
229 reset_control_assert(priv
->rst
);
231 clk_disable_unprepare(priv
->clk
);
233 clk_disable_unprepare(priv
->clk_ext
);
238 static int uniphier_u3hsphy_power_off(struct phy
*phy
)
240 struct uniphier_u3hsphy_priv
*priv
= phy_get_drvdata(phy
);
243 regulator_disable(priv
->vbus
);
245 reset_control_assert(priv
->rst
);
246 clk_disable_unprepare(priv
->clk
);
247 clk_disable_unprepare(priv
->clk_ext
);
252 static int uniphier_u3hsphy_init(struct phy
*phy
)
254 struct uniphier_u3hsphy_priv
*priv
= phy_get_drvdata(phy
);
255 u32 config0
, config1
;
258 ret
= clk_prepare_enable(priv
->clk_parent
);
262 ret
= clk_prepare_enable(priv
->clk_parent_gio
);
264 goto out_clk_disable
;
266 ret
= reset_control_deassert(priv
->rst_parent
);
268 goto out_clk_gio_disable
;
270 ret
= reset_control_deassert(priv
->rst_parent_gio
);
274 if ((priv
->data
->is_legacy
)
275 || (!priv
->data
->config0
&& !priv
->data
->config1
))
278 config0
= priv
->data
->config0
;
279 config1
= priv
->data
->config1
;
281 ret
= uniphier_u3hsphy_update_config(priv
, &config0
);
285 writel(config0
, priv
->base
+ HSPHY_CFG0
);
286 writel(config1
, priv
->base
+ HSPHY_CFG1
);
288 for (i
= 0; i
< priv
->data
->nparams
; i
++)
289 uniphier_u3hsphy_set_param(priv
, &priv
->data
->param
[i
]);
294 reset_control_assert(priv
->rst_parent
);
296 clk_disable_unprepare(priv
->clk_parent_gio
);
298 clk_disable_unprepare(priv
->clk_parent
);
303 static int uniphier_u3hsphy_exit(struct phy
*phy
)
305 struct uniphier_u3hsphy_priv
*priv
= phy_get_drvdata(phy
);
307 reset_control_assert(priv
->rst_parent_gio
);
308 reset_control_assert(priv
->rst_parent
);
309 clk_disable_unprepare(priv
->clk_parent_gio
);
310 clk_disable_unprepare(priv
->clk_parent
);
315 static const struct phy_ops uniphier_u3hsphy_ops
= {
316 .init
= uniphier_u3hsphy_init
,
317 .exit
= uniphier_u3hsphy_exit
,
318 .power_on
= uniphier_u3hsphy_power_on
,
319 .power_off
= uniphier_u3hsphy_power_off
,
320 .owner
= THIS_MODULE
,
323 static int uniphier_u3hsphy_probe(struct platform_device
*pdev
)
325 struct device
*dev
= &pdev
->dev
;
326 struct uniphier_u3hsphy_priv
*priv
;
327 struct phy_provider
*phy_provider
;
330 priv
= devm_kzalloc(dev
, sizeof(*priv
), GFP_KERNEL
);
335 priv
->data
= of_device_get_match_data(dev
);
336 if (WARN_ON(!priv
->data
||
337 priv
->data
->nparams
> MAX_PHY_PARAMS
))
340 priv
->base
= devm_platform_ioremap_resource(pdev
, 0);
341 if (IS_ERR(priv
->base
))
342 return PTR_ERR(priv
->base
);
344 if (!priv
->data
->is_legacy
) {
345 priv
->clk
= devm_clk_get(dev
, "phy");
346 if (IS_ERR(priv
->clk
))
347 return PTR_ERR(priv
->clk
);
349 priv
->clk_ext
= devm_clk_get_optional(dev
, "phy-ext");
350 if (IS_ERR(priv
->clk_ext
))
351 return PTR_ERR(priv
->clk_ext
);
353 priv
->rst
= devm_reset_control_get_shared(dev
, "phy");
354 if (IS_ERR(priv
->rst
))
355 return PTR_ERR(priv
->rst
);
358 priv
->clk_parent_gio
= devm_clk_get(dev
, "gio");
359 if (IS_ERR(priv
->clk_parent_gio
))
360 return PTR_ERR(priv
->clk_parent_gio
);
362 priv
->rst_parent_gio
=
363 devm_reset_control_get_shared(dev
, "gio");
364 if (IS_ERR(priv
->rst_parent_gio
))
365 return PTR_ERR(priv
->rst_parent_gio
);
368 priv
->clk_parent
= devm_clk_get(dev
, "link");
369 if (IS_ERR(priv
->clk_parent
))
370 return PTR_ERR(priv
->clk_parent
);
372 priv
->rst_parent
= devm_reset_control_get_shared(dev
, "link");
373 if (IS_ERR(priv
->rst_parent
))
374 return PTR_ERR(priv
->rst_parent
);
376 priv
->vbus
= devm_regulator_get_optional(dev
, "vbus");
377 if (IS_ERR(priv
->vbus
)) {
378 if (PTR_ERR(priv
->vbus
) == -EPROBE_DEFER
)
379 return PTR_ERR(priv
->vbus
);
383 phy
= devm_phy_create(dev
, dev
->of_node
, &uniphier_u3hsphy_ops
);
387 phy_set_drvdata(phy
, priv
);
388 phy_provider
= devm_of_phy_provider_register(dev
, of_phy_simple_xlate
);
390 return PTR_ERR_OR_ZERO(phy_provider
);
393 static const struct uniphier_u3hsphy_soc_data uniphier_pro5_data
= {
398 static const struct uniphier_u3hsphy_soc_data uniphier_pxs2_data
= {
407 static const struct uniphier_u3hsphy_soc_data uniphier_ld20_data
= {
416 .trim_func
= uniphier_u3hsphy_trim_ld20
,
417 .config0
= 0x92316680,
418 .config1
= 0x00000106,
421 static const struct uniphier_u3hsphy_soc_data uniphier_pxs3_data
= {
428 .trim_func
= uniphier_u3hsphy_trim_ld20
,
429 .config0
= 0x92316680,
430 .config1
= 0x00000106,
433 static const struct of_device_id uniphier_u3hsphy_match
[] = {
435 .compatible
= "socionext,uniphier-pro5-usb3-hsphy",
436 .data
= &uniphier_pro5_data
,
439 .compatible
= "socionext,uniphier-pxs2-usb3-hsphy",
440 .data
= &uniphier_pxs2_data
,
443 .compatible
= "socionext,uniphier-ld20-usb3-hsphy",
444 .data
= &uniphier_ld20_data
,
447 .compatible
= "socionext,uniphier-pxs3-usb3-hsphy",
448 .data
= &uniphier_pxs3_data
,
452 MODULE_DEVICE_TABLE(of
, uniphier_u3hsphy_match
);
454 static struct platform_driver uniphier_u3hsphy_driver
= {
455 .probe
= uniphier_u3hsphy_probe
,
457 .name
= "uniphier-usb3-hsphy",
458 .of_match_table
= uniphier_u3hsphy_match
,
462 module_platform_driver(uniphier_u3hsphy_driver
);
464 MODULE_AUTHOR("Kunihiko Hayashi <hayashi.kunihiko@socionext.com>");
465 MODULE_DESCRIPTION("UniPhier HS-PHY driver for USB3 controller");
466 MODULE_LICENSE("GPL v2");