Linux 6.9-rc1
[linux-2.6-microblaze.git] / drivers / phy / socionext / phy-uniphier-usb3hs.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * phy-uniphier-usb3hs.c - HS-PHY driver for Socionext UniPhier USB3 controller
4  * Copyright 2015-2018 Socionext Inc.
5  * Author:
6  *      Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
7  * Contributors:
8  *      Motoya Tanigawa <tanigawa.motoya@socionext.com>
9  *      Masami Hiramatsu <masami.hiramatsu@linaro.org>
10  */
11
12 #include <linux/bitfield.h>
13 #include <linux/bitops.h>
14 #include <linux/clk.h>
15 #include <linux/io.h>
16 #include <linux/module.h>
17 #include <linux/nvmem-consumer.h>
18 #include <linux/of.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>
25
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)
35
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)
41
42 #define PHY_F(regno, msb, lsb) { (regno), (msb), (lsb) }
43
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 */
48
49 #define MAX_PHY_PARAMS  4
50
51 struct uniphier_u3hsphy_param {
52         struct {
53                 int reg_no;
54                 int msb;
55                 int lsb;
56         } field;
57         u8 value;
58 };
59
60 struct uniphier_u3hsphy_trim_param {
61         unsigned int rterm;
62         unsigned int sel_t;
63         unsigned int hs_i;
64 };
65
66 #define trim_param_is_valid(p)  ((p)->rterm || (p)->sel_t || (p)->hs_i)
67
68 struct uniphier_u3hsphy_priv {
69         struct device *dev;
70         void __iomem *base;
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;
75 };
76
77 struct uniphier_u3hsphy_soc_data {
78         bool is_legacy;
79         int nparams;
80         const struct uniphier_u3hsphy_param param[MAX_PHY_PARAMS];
81         u32 config0;
82         u32 config1;
83         void (*trim_func)(struct uniphier_u3hsphy_priv *priv, u32 *pconfig,
84                           struct uniphier_u3hsphy_trim_param *pt);
85 };
86
87 static void uniphier_u3hsphy_trim_ld20(struct uniphier_u3hsphy_priv *priv,
88                                        u32 *pconfig,
89                                        struct uniphier_u3hsphy_trim_param *pt)
90 {
91         *pconfig &= ~HSPHY_CFG0_RTERM_MASK;
92         *pconfig |= FIELD_PREP(HSPHY_CFG0_RTERM_MASK, pt->rterm);
93
94         *pconfig &= ~HSPHY_CFG0_SEL_T_MASK;
95         *pconfig |= FIELD_PREP(HSPHY_CFG0_SEL_T_MASK, pt->sel_t);
96
97         *pconfig &= ~HSPHY_CFG0_HS_I_MASK;
98         *pconfig |= FIELD_PREP(HSPHY_CFG0_HS_I_MASK,  pt->hs_i);
99 }
100
101 static int uniphier_u3hsphy_get_nvparam(struct uniphier_u3hsphy_priv *priv,
102                                         const char *name, unsigned int *val)
103 {
104         struct nvmem_cell *cell;
105         u8 *buf;
106
107         cell = devm_nvmem_cell_get(priv->dev, name);
108         if (IS_ERR(cell))
109                 return PTR_ERR(cell);
110
111         buf = nvmem_cell_read(cell, NULL);
112         if (IS_ERR(buf))
113                 return PTR_ERR(buf);
114
115         *val = *buf;
116
117         kfree(buf);
118
119         return 0;
120 }
121
122 static int uniphier_u3hsphy_get_nvparams(struct uniphier_u3hsphy_priv *priv,
123                                          struct uniphier_u3hsphy_trim_param *pt)
124 {
125         int ret;
126
127         ret = uniphier_u3hsphy_get_nvparam(priv, "rterm", &pt->rterm);
128         if (ret)
129                 return ret;
130
131         ret = uniphier_u3hsphy_get_nvparam(priv, "sel_t", &pt->sel_t);
132         if (ret)
133                 return ret;
134
135         ret = uniphier_u3hsphy_get_nvparam(priv, "hs_i", &pt->hs_i);
136         if (ret)
137                 return ret;
138
139         return 0;
140 }
141
142 static int uniphier_u3hsphy_update_config(struct uniphier_u3hsphy_priv *priv,
143                                           u32 *pconfig)
144 {
145         struct uniphier_u3hsphy_trim_param trim;
146         int ret, trimmed = 0;
147
148         if (priv->data->trim_func) {
149                 ret = uniphier_u3hsphy_get_nvparams(priv, &trim);
150                 if (ret == -EPROBE_DEFER)
151                         return ret;
152
153                 /*
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.
157                  */
158                 if (!ret && trim_param_is_valid(&trim)) {
159                         priv->data->trim_func(priv, pconfig, &trim);
160                         trimmed = 1;
161                 } else {
162                         dev_dbg(priv->dev, "can't get parameter from nvmem\n");
163                 }
164         }
165
166         /* use default parameters without trimming values */
167         if (!trimmed) {
168                 *pconfig &= ~HSPHY_CFG0_HSDISC_MASK;
169                 *pconfig |= FIELD_PREP(HSPHY_CFG0_HSDISC_MASK, 3);
170         }
171
172         return 0;
173 }
174
175 static void uniphier_u3hsphy_set_param(struct uniphier_u3hsphy_priv *priv,
176                                        const struct uniphier_u3hsphy_param *p)
177 {
178         u32 val;
179         u32 field_mask = GENMASK(p->field.msb, p->field.lsb);
180         u8 data;
181
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)
185                 | HSPHY_CFG1_ADR_EN;
186         writel(val, priv->base + HSPHY_CFG1);
187
188         val = readl(priv->base + HSPHY_CFG1);
189         val &= ~HSPHY_CFG1_ADR_EN;
190         writel(val, priv->base + HSPHY_CFG1);
191
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);
197
198         val = readl(priv->base + HSPHY_CFG1);
199         val &= ~HSPHY_CFG1_DAT_EN;
200         writel(val, priv->base + HSPHY_CFG1);
201 }
202
203 static int uniphier_u3hsphy_power_on(struct phy *phy)
204 {
205         struct uniphier_u3hsphy_priv *priv = phy_get_drvdata(phy);
206         int ret;
207
208         ret = clk_prepare_enable(priv->clk_ext);
209         if (ret)
210                 return ret;
211
212         ret = clk_prepare_enable(priv->clk);
213         if (ret)
214                 goto out_clk_ext_disable;
215
216         ret = reset_control_deassert(priv->rst);
217         if (ret)
218                 goto out_clk_disable;
219
220         if (priv->vbus) {
221                 ret = regulator_enable(priv->vbus);
222                 if (ret)
223                         goto out_rst_assert;
224         }
225
226         return 0;
227
228 out_rst_assert:
229         reset_control_assert(priv->rst);
230 out_clk_disable:
231         clk_disable_unprepare(priv->clk);
232 out_clk_ext_disable:
233         clk_disable_unprepare(priv->clk_ext);
234
235         return ret;
236 }
237
238 static int uniphier_u3hsphy_power_off(struct phy *phy)
239 {
240         struct uniphier_u3hsphy_priv *priv = phy_get_drvdata(phy);
241
242         if (priv->vbus)
243                 regulator_disable(priv->vbus);
244
245         reset_control_assert(priv->rst);
246         clk_disable_unprepare(priv->clk);
247         clk_disable_unprepare(priv->clk_ext);
248
249         return 0;
250 }
251
252 static int uniphier_u3hsphy_init(struct phy *phy)
253 {
254         struct uniphier_u3hsphy_priv *priv = phy_get_drvdata(phy);
255         u32 config0, config1;
256         int i, ret;
257
258         ret = clk_prepare_enable(priv->clk_parent);
259         if (ret)
260                 return ret;
261
262         ret = clk_prepare_enable(priv->clk_parent_gio);
263         if (ret)
264                 goto out_clk_disable;
265
266         ret = reset_control_deassert(priv->rst_parent);
267         if (ret)
268                 goto out_clk_gio_disable;
269
270         ret = reset_control_deassert(priv->rst_parent_gio);
271         if (ret)
272                 goto out_rst_assert;
273
274         if ((priv->data->is_legacy)
275             || (!priv->data->config0 && !priv->data->config1))
276                 return 0;
277
278         config0 = priv->data->config0;
279         config1 = priv->data->config1;
280
281         ret = uniphier_u3hsphy_update_config(priv, &config0);
282         if (ret)
283                 goto out_rst_assert;
284
285         writel(config0, priv->base + HSPHY_CFG0);
286         writel(config1, priv->base + HSPHY_CFG1);
287
288         for (i = 0; i < priv->data->nparams; i++)
289                 uniphier_u3hsphy_set_param(priv, &priv->data->param[i]);
290
291         return 0;
292
293 out_rst_assert:
294         reset_control_assert(priv->rst_parent);
295 out_clk_gio_disable:
296         clk_disable_unprepare(priv->clk_parent_gio);
297 out_clk_disable:
298         clk_disable_unprepare(priv->clk_parent);
299
300         return ret;
301 }
302
303 static int uniphier_u3hsphy_exit(struct phy *phy)
304 {
305         struct uniphier_u3hsphy_priv *priv = phy_get_drvdata(phy);
306
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);
311
312         return 0;
313 }
314
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,
321 };
322
323 static int uniphier_u3hsphy_probe(struct platform_device *pdev)
324 {
325         struct device *dev = &pdev->dev;
326         struct uniphier_u3hsphy_priv *priv;
327         struct phy_provider *phy_provider;
328         struct phy *phy;
329
330         priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
331         if (!priv)
332                 return -ENOMEM;
333
334         priv->dev = dev;
335         priv->data = of_device_get_match_data(dev);
336         if (WARN_ON(!priv->data ||
337                     priv->data->nparams > MAX_PHY_PARAMS))
338                 return -EINVAL;
339
340         priv->base = devm_platform_ioremap_resource(pdev, 0);
341         if (IS_ERR(priv->base))
342                 return PTR_ERR(priv->base);
343
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);
348
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);
352
353                 priv->rst = devm_reset_control_get_shared(dev, "phy");
354                 if (IS_ERR(priv->rst))
355                         return PTR_ERR(priv->rst);
356
357         } else {
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);
361
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);
366         }
367
368         priv->clk_parent = devm_clk_get(dev, "link");
369         if (IS_ERR(priv->clk_parent))
370                 return PTR_ERR(priv->clk_parent);
371
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);
375
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);
380                 priv->vbus = NULL;
381         }
382
383         phy = devm_phy_create(dev, dev->of_node, &uniphier_u3hsphy_ops);
384         if (IS_ERR(phy))
385                 return PTR_ERR(phy);
386
387         phy_set_drvdata(phy, priv);
388         phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
389
390         return PTR_ERR_OR_ZERO(phy_provider);
391 }
392
393 static const struct uniphier_u3hsphy_soc_data uniphier_pro5_data = {
394         .is_legacy = true,
395         .nparams = 0,
396 };
397
398 static const struct uniphier_u3hsphy_soc_data uniphier_pxs2_data = {
399         .is_legacy = false,
400         .nparams = 2,
401         .param = {
402                 { RX_CHK_SYNC, 1 },
403                 { RX_SYNC_SEL, 1 },
404         },
405 };
406
407 static const struct uniphier_u3hsphy_soc_data uniphier_ld20_data = {
408         .is_legacy = false,
409         .nparams = 4,
410         .param = {
411                 { RX_CHK_SYNC, 1 },
412                 { RX_SYNC_SEL, 1 },
413                 { LS_SLEW, 1 },
414                 { FS_LS_DRV, 1 },
415         },
416         .trim_func = uniphier_u3hsphy_trim_ld20,
417         .config0 = 0x92316680,
418         .config1 = 0x00000106,
419 };
420
421 static const struct uniphier_u3hsphy_soc_data uniphier_pxs3_data = {
422         .is_legacy = false,
423         .nparams = 2,
424         .param = {
425                 { RX_CHK_SYNC, 1 },
426                 { RX_SYNC_SEL, 1 },
427         },
428         .trim_func = uniphier_u3hsphy_trim_ld20,
429         .config0 = 0x92316680,
430         .config1 = 0x00000106,
431 };
432
433 static const struct of_device_id uniphier_u3hsphy_match[] = {
434         {
435                 .compatible = "socionext,uniphier-pro5-usb3-hsphy",
436                 .data = &uniphier_pro5_data,
437         },
438         {
439                 .compatible = "socionext,uniphier-pxs2-usb3-hsphy",
440                 .data = &uniphier_pxs2_data,
441         },
442         {
443                 .compatible = "socionext,uniphier-ld20-usb3-hsphy",
444                 .data = &uniphier_ld20_data,
445         },
446         {
447                 .compatible = "socionext,uniphier-pxs3-usb3-hsphy",
448                 .data = &uniphier_pxs3_data,
449         },
450         { /* sentinel */ }
451 };
452 MODULE_DEVICE_TABLE(of, uniphier_u3hsphy_match);
453
454 static struct platform_driver uniphier_u3hsphy_driver = {
455         .probe = uniphier_u3hsphy_probe,
456         .driver = {
457                 .name = "uniphier-usb3-hsphy",
458                 .of_match_table = uniphier_u3hsphy_match,
459         },
460 };
461
462 module_platform_driver(uniphier_u3hsphy_driver);
463
464 MODULE_AUTHOR("Kunihiko Hayashi <hayashi.kunihiko@socionext.com>");
465 MODULE_DESCRIPTION("UniPhier HS-PHY driver for USB3 controller");
466 MODULE_LICENSE("GPL v2");