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 LS_SLEW PHY_F(10, 6, 6) /* LS mode slew rate */
45 #define FS_LS_DRV PHY_F(10, 5, 5) /* FS/LS slew rate */
47 #define MAX_PHY_PARAMS 2
49 struct uniphier_u3hsphy_param
{
58 struct uniphier_u3hsphy_trim_param
{
64 #define trim_param_is_valid(p) ((p)->rterm || (p)->sel_t || (p)->hs_i)
66 struct uniphier_u3hsphy_priv
{
69 struct clk
*clk
, *clk_parent
, *clk_ext
;
70 struct reset_control
*rst
, *rst_parent
;
71 struct regulator
*vbus
;
72 const struct uniphier_u3hsphy_soc_data
*data
;
75 struct uniphier_u3hsphy_soc_data
{
77 const struct uniphier_u3hsphy_param param
[MAX_PHY_PARAMS
];
80 void (*trim_func
)(struct uniphier_u3hsphy_priv
*priv
, u32
*pconfig
,
81 struct uniphier_u3hsphy_trim_param
*pt
);
84 static void uniphier_u3hsphy_trim_ld20(struct uniphier_u3hsphy_priv
*priv
,
86 struct uniphier_u3hsphy_trim_param
*pt
)
88 *pconfig
&= ~HSPHY_CFG0_RTERM_MASK
;
89 *pconfig
|= FIELD_PREP(HSPHY_CFG0_RTERM_MASK
, pt
->rterm
);
91 *pconfig
&= ~HSPHY_CFG0_SEL_T_MASK
;
92 *pconfig
|= FIELD_PREP(HSPHY_CFG0_SEL_T_MASK
, pt
->sel_t
);
94 *pconfig
&= ~HSPHY_CFG0_HS_I_MASK
;
95 *pconfig
|= FIELD_PREP(HSPHY_CFG0_HS_I_MASK
, pt
->hs_i
);
98 static int uniphier_u3hsphy_get_nvparam(struct uniphier_u3hsphy_priv
*priv
,
99 const char *name
, unsigned int *val
)
101 struct nvmem_cell
*cell
;
104 cell
= devm_nvmem_cell_get(priv
->dev
, name
);
106 return PTR_ERR(cell
);
108 buf
= nvmem_cell_read(cell
, NULL
);
119 static int uniphier_u3hsphy_get_nvparams(struct uniphier_u3hsphy_priv
*priv
,
120 struct uniphier_u3hsphy_trim_param
*pt
)
124 ret
= uniphier_u3hsphy_get_nvparam(priv
, "rterm", &pt
->rterm
);
128 ret
= uniphier_u3hsphy_get_nvparam(priv
, "sel_t", &pt
->sel_t
);
132 ret
= uniphier_u3hsphy_get_nvparam(priv
, "hs_i", &pt
->hs_i
);
139 static int uniphier_u3hsphy_update_config(struct uniphier_u3hsphy_priv
*priv
,
142 struct uniphier_u3hsphy_trim_param trim
;
143 int ret
, trimmed
= 0;
145 if (priv
->data
->trim_func
) {
146 ret
= uniphier_u3hsphy_get_nvparams(priv
, &trim
);
147 if (ret
== -EPROBE_DEFER
)
151 * call trim_func only when trimming parameters that aren't
152 * all-zero can be acquired. All-zero parameters mean nothing
153 * has been written to nvmem.
155 if (!ret
&& trim_param_is_valid(&trim
)) {
156 priv
->data
->trim_func(priv
, pconfig
, &trim
);
159 dev_dbg(priv
->dev
, "can't get parameter from nvmem\n");
163 /* use default parameters without trimming values */
165 *pconfig
&= ~HSPHY_CFG0_HSDISC_MASK
;
166 *pconfig
|= FIELD_PREP(HSPHY_CFG0_HSDISC_MASK
, 3);
172 static void uniphier_u3hsphy_set_param(struct uniphier_u3hsphy_priv
*priv
,
173 const struct uniphier_u3hsphy_param
*p
)
176 u32 field_mask
= GENMASK(p
->field
.msb
, p
->field
.lsb
);
179 val
= readl(priv
->base
+ HSPHY_CFG1
);
180 val
&= ~HSPHY_CFG1_ADR_MASK
;
181 val
|= FIELD_PREP(HSPHY_CFG1_ADR_MASK
, p
->field
.reg_no
)
183 writel(val
, priv
->base
+ HSPHY_CFG1
);
185 val
= readl(priv
->base
+ HSPHY_CFG1
);
186 val
&= ~HSPHY_CFG1_ADR_EN
;
187 writel(val
, priv
->base
+ HSPHY_CFG1
);
189 val
= readl(priv
->base
+ HSPHY_CFG1
);
190 val
&= ~FIELD_PREP(HSPHY_CFG1_DAT_MASK
, field_mask
);
191 data
= field_mask
& (p
->value
<< p
->field
.lsb
);
192 val
|= FIELD_PREP(HSPHY_CFG1_DAT_MASK
, data
) | HSPHY_CFG1_DAT_EN
;
193 writel(val
, priv
->base
+ HSPHY_CFG1
);
195 val
= readl(priv
->base
+ HSPHY_CFG1
);
196 val
&= ~HSPHY_CFG1_DAT_EN
;
197 writel(val
, priv
->base
+ HSPHY_CFG1
);
200 static int uniphier_u3hsphy_power_on(struct phy
*phy
)
202 struct uniphier_u3hsphy_priv
*priv
= phy_get_drvdata(phy
);
205 ret
= clk_prepare_enable(priv
->clk_ext
);
209 ret
= clk_prepare_enable(priv
->clk
);
211 goto out_clk_ext_disable
;
213 ret
= reset_control_deassert(priv
->rst
);
215 goto out_clk_disable
;
218 ret
= regulator_enable(priv
->vbus
);
226 reset_control_assert(priv
->rst
);
228 clk_disable_unprepare(priv
->clk
);
230 clk_disable_unprepare(priv
->clk_ext
);
235 static int uniphier_u3hsphy_power_off(struct phy
*phy
)
237 struct uniphier_u3hsphy_priv
*priv
= phy_get_drvdata(phy
);
240 regulator_disable(priv
->vbus
);
242 reset_control_assert(priv
->rst
);
243 clk_disable_unprepare(priv
->clk
);
244 clk_disable_unprepare(priv
->clk_ext
);
249 static int uniphier_u3hsphy_init(struct phy
*phy
)
251 struct uniphier_u3hsphy_priv
*priv
= phy_get_drvdata(phy
);
252 u32 config0
, config1
;
255 ret
= clk_prepare_enable(priv
->clk_parent
);
259 ret
= reset_control_deassert(priv
->rst_parent
);
261 goto out_clk_disable
;
263 if (!priv
->data
->config0
&& !priv
->data
->config1
)
266 config0
= priv
->data
->config0
;
267 config1
= priv
->data
->config1
;
269 ret
= uniphier_u3hsphy_update_config(priv
, &config0
);
273 writel(config0
, priv
->base
+ HSPHY_CFG0
);
274 writel(config1
, priv
->base
+ HSPHY_CFG1
);
276 for (i
= 0; i
< priv
->data
->nparams
; i
++)
277 uniphier_u3hsphy_set_param(priv
, &priv
->data
->param
[i
]);
282 reset_control_assert(priv
->rst_parent
);
284 clk_disable_unprepare(priv
->clk_parent
);
289 static int uniphier_u3hsphy_exit(struct phy
*phy
)
291 struct uniphier_u3hsphy_priv
*priv
= phy_get_drvdata(phy
);
293 reset_control_assert(priv
->rst_parent
);
294 clk_disable_unprepare(priv
->clk_parent
);
299 static const struct phy_ops uniphier_u3hsphy_ops
= {
300 .init
= uniphier_u3hsphy_init
,
301 .exit
= uniphier_u3hsphy_exit
,
302 .power_on
= uniphier_u3hsphy_power_on
,
303 .power_off
= uniphier_u3hsphy_power_off
,
304 .owner
= THIS_MODULE
,
307 static int uniphier_u3hsphy_probe(struct platform_device
*pdev
)
309 struct device
*dev
= &pdev
->dev
;
310 struct uniphier_u3hsphy_priv
*priv
;
311 struct phy_provider
*phy_provider
;
312 struct resource
*res
;
315 priv
= devm_kzalloc(dev
, sizeof(*priv
), GFP_KERNEL
);
320 priv
->data
= of_device_get_match_data(dev
);
321 if (WARN_ON(!priv
->data
||
322 priv
->data
->nparams
> MAX_PHY_PARAMS
))
325 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
326 priv
->base
= devm_ioremap_resource(dev
, res
);
327 if (IS_ERR(priv
->base
))
328 return PTR_ERR(priv
->base
);
330 priv
->clk
= devm_clk_get(dev
, "phy");
331 if (IS_ERR(priv
->clk
))
332 return PTR_ERR(priv
->clk
);
334 priv
->clk_parent
= devm_clk_get(dev
, "link");
335 if (IS_ERR(priv
->clk_parent
))
336 return PTR_ERR(priv
->clk_parent
);
338 priv
->clk_ext
= devm_clk_get_optional(dev
, "phy-ext");
339 if (IS_ERR(priv
->clk_ext
))
340 return PTR_ERR(priv
->clk_ext
);
342 priv
->rst
= devm_reset_control_get_shared(dev
, "phy");
343 if (IS_ERR(priv
->rst
))
344 return PTR_ERR(priv
->rst
);
346 priv
->rst_parent
= devm_reset_control_get_shared(dev
, "link");
347 if (IS_ERR(priv
->rst_parent
))
348 return PTR_ERR(priv
->rst_parent
);
350 priv
->vbus
= devm_regulator_get_optional(dev
, "vbus");
351 if (IS_ERR(priv
->vbus
)) {
352 if (PTR_ERR(priv
->vbus
) == -EPROBE_DEFER
)
353 return PTR_ERR(priv
->vbus
);
357 phy
= devm_phy_create(dev
, dev
->of_node
, &uniphier_u3hsphy_ops
);
361 phy_set_drvdata(phy
, priv
);
362 phy_provider
= devm_of_phy_provider_register(dev
, of_phy_simple_xlate
);
364 return PTR_ERR_OR_ZERO(phy_provider
);
367 static const struct uniphier_u3hsphy_soc_data uniphier_pxs2_data
= {
371 static const struct uniphier_u3hsphy_soc_data uniphier_ld20_data
= {
377 .trim_func
= uniphier_u3hsphy_trim_ld20
,
378 .config0
= 0x92316680,
379 .config1
= 0x00000106,
382 static const struct uniphier_u3hsphy_soc_data uniphier_pxs3_data
= {
384 .trim_func
= uniphier_u3hsphy_trim_ld20
,
385 .config0
= 0x92316680,
386 .config1
= 0x00000106,
389 static const struct of_device_id uniphier_u3hsphy_match
[] = {
391 .compatible
= "socionext,uniphier-pxs2-usb3-hsphy",
392 .data
= &uniphier_pxs2_data
,
395 .compatible
= "socionext,uniphier-ld20-usb3-hsphy",
396 .data
= &uniphier_ld20_data
,
399 .compatible
= "socionext,uniphier-pxs3-usb3-hsphy",
400 .data
= &uniphier_pxs3_data
,
404 MODULE_DEVICE_TABLE(of
, uniphier_u3hsphy_match
);
406 static struct platform_driver uniphier_u3hsphy_driver
= {
407 .probe
= uniphier_u3hsphy_probe
,
409 .name
= "uniphier-usb3-hsphy",
410 .of_match_table
= uniphier_u3hsphy_match
,
414 module_platform_driver(uniphier_u3hsphy_driver
);
416 MODULE_AUTHOR("Kunihiko Hayashi <hayashi.kunihiko@socionext.com>");
417 MODULE_DESCRIPTION("UniPhier HS-PHY driver for USB3 controller");
418 MODULE_LICENSE("GPL v2");