phy: marvell: a3700: Convert to official DT bindings in COMPHY driver
[platform/kernel/u-boot.git] / drivers / phy / phy-imx8mq-usb.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright 2021 NXP
4  *
5  */
6
7 #include <common.h>
8 #include <asm/io.h>
9 #include <dm.h>
10 #include <errno.h>
11 #include <generic-phy.h>
12 #include <linux/bitops.h>
13 #include <linux/err.h>
14 #include <clk.h>
15
16 #define PHY_CTRL0                       0x0
17 #define PHY_CTRL0_REF_SSP_EN            BIT(2)
18 #define PHY_CTRL0_FSEL_MASK             GENMASK(10, 5)
19 #define PHY_CTRL0_FSEL_24M              0x2a
20 #define PHY_CTRL0_FSEL_100M             0x27
21 #define PHY_CTRL0_SSC_RANGE_MASK        GENMASK(23, 21)
22 #define PHY_CTRL0_SSC_RANGE_4003PPM     (0x2 << 21)
23
24 #define PHY_CTRL1                       0x4
25 #define PHY_CTRL1_RESET                 BIT(0)
26 #define PHY_CTRL1_COMMONONN             BIT(1)
27 #define PHY_CTRL1_ATERESET              BIT(3)
28 #define PHY_CTRL1_DCDENB                BIT(17)
29 #define PHY_CTRL1_CHRGSEL               BIT(18)
30 #define PHY_CTRL1_VDATSRCENB0           BIT(19)
31 #define PHY_CTRL1_VDATDETENB0           BIT(20)
32
33 #define PHY_CTRL2                       0x8
34 #define PHY_CTRL2_TXENABLEN0            BIT(8)
35 #define PHY_CTRL2_OTG_DISABLE           BIT(9)
36
37 #define PHY_CTRL3                       0xc
38 #define PHY_CTRL3_COMPDISTUNE_MASK      GENMASK(2, 0)
39 #define PHY_CTRL3_TXPREEMP_TUNE_MASK    GENMASK(16, 15)
40 #define PHY_CTRL3_TXPREEMP_TUNE_SHIFT   15
41 #define PHY_CTRL3_TXRISE_TUNE_MASK      GENMASK(21, 20)
42 #define PHY_CTRL3_TXRISE_TUNE_SHIFT     20
43 /* 1111: +24% ... 0000: -6% step: 2% */
44 #define PHY_CTRL3_TXVREF_TUNE_MASK      GENMASK(25, 22)
45 #define PHY_CTRL3_TXVREF_TUNE_SHIFT     22
46 #define PHY_CTRL3_TX_VBOOST_LEVEL_MASK  GENMASK(31, 29)
47 #define PHY_CTRL3_TX_VBOOST_LEVEL_SHIFT 29
48
49 #define PHY_CTRL4                       0x10
50 #define PHY_CTRL4_PCS_TX_DEEMPH_3P5DB_MASK      GENMASK(20, 15)
51 #define PHY_CTRL4_PCS_TX_DEEMPH_3P5DB_SHIFT     15
52
53 #define PHY_CTRL5                       0x14
54 #define PHY_CTRL5_DMPWD_OVERRIDE_SEL    BIT(23)
55 #define PHY_CTRL5_DMPWD_OVERRIDE        BIT(22)
56 #define PHY_CTRL5_DPPWD_OVERRIDE_SEL    BIT(21)
57 #define PHY_CTRL5_DPPWD_OVERRIDE        BIT(20)
58 #define PHY_CTRL5_PCS_TX_SWING_FULL_MASK        GENMASK(6, 0)
59
60 #define PHY_CTRL6                       0x18
61 #define PHY_CTRL6_RXTERM_OVERRIDE_SEL   BIT(29)
62 #define PHY_CTRL6_ALT_CLK_EN            BIT(1)
63 #define PHY_CTRL6_ALT_CLK_SEL           BIT(0)
64
65 #define PHY_STS0                        0x40
66 #define PHY_STS0_OTGSESSVLD             BIT(7)
67 #define PHY_STS0_CHGDET                 BIT(4)
68 #define PHY_STS0_FSVPLUS                BIT(3)
69 #define PHY_STS0_FSVMINUS               BIT(2)
70
71 struct imx8mq_usb_phy {
72 #if CONFIG_IS_ENABLED(CLK)
73         struct clk phy_clk;
74 #endif
75         void __iomem *base;
76 };
77
78 static const struct udevice_id imx8mq_usb_phy_of_match[] = {
79         {
80                 .compatible = "fsl,imx8mq-usb-phy",
81         },
82         {},
83 };
84
85 static int imx8mq_usb_phy_init(struct phy *usb_phy)
86 {
87         struct udevice *dev = usb_phy->dev;
88         struct imx8mq_usb_phy *imx_phy = dev_get_priv(dev);
89         u32 value;
90
91         value = readl(imx_phy->base + PHY_CTRL1);
92         value &= ~(PHY_CTRL1_VDATSRCENB0 | PHY_CTRL1_VDATDETENB0 |
93                    PHY_CTRL1_COMMONONN);
94         value |= PHY_CTRL1_RESET | PHY_CTRL1_ATERESET;
95         writel(value, imx_phy->base + PHY_CTRL1);
96
97         value = readl(imx_phy->base + PHY_CTRL0);
98         value |= PHY_CTRL0_REF_SSP_EN;
99         value &= ~PHY_CTRL0_SSC_RANGE_MASK;
100         value |= PHY_CTRL0_SSC_RANGE_4003PPM;
101         writel(value, imx_phy->base + PHY_CTRL0);
102
103         value = readl(imx_phy->base + PHY_CTRL2);
104         value |= PHY_CTRL2_TXENABLEN0;
105         writel(value, imx_phy->base + PHY_CTRL2);
106
107         value = readl(imx_phy->base + PHY_CTRL1);
108         value &= ~(PHY_CTRL1_RESET | PHY_CTRL1_ATERESET);
109         writel(value, imx_phy->base + PHY_CTRL1);
110
111         return 0;
112 }
113
114 static int imx8mq_usb_phy_power_on(struct phy *usb_phy)
115 {
116         struct udevice *dev = usb_phy->dev;
117         struct imx8mq_usb_phy *imx_phy = dev_get_priv(dev);
118         u32 value;
119
120 #if CONFIG_IS_ENABLED(CLK)
121         int ret;
122         ret = clk_enable(&imx_phy->phy_clk);
123         if (ret) {
124                 printf("Failed to enable usb phy clock\n");
125                 return ret;
126         }
127 #endif
128
129         /* Disable rx term override */
130         value = readl(imx_phy->base + PHY_CTRL6);
131         value &= ~PHY_CTRL6_RXTERM_OVERRIDE_SEL;
132         writel(value, imx_phy->base + PHY_CTRL6);
133
134         return 0;
135 }
136
137 static int imx8mq_usb_phy_power_off(struct phy *usb_phy)
138 {
139         struct udevice *dev = usb_phy->dev;
140         struct imx8mq_usb_phy *imx_phy = dev_get_priv(dev);
141         u32 value;
142
143         /* Override rx term to be 0 */
144         value = readl(imx_phy->base + PHY_CTRL6);
145         value |= PHY_CTRL6_RXTERM_OVERRIDE_SEL;
146         writel(value, imx_phy->base + PHY_CTRL6);
147
148 #if CONFIG_IS_ENABLED(CLK)
149         clk_disable(&imx_phy->phy_clk);
150 #endif
151
152         return 0;
153 }
154
155 static int imx8mq_usb_phy_exit(struct phy *usb_phy)
156 {
157         return imx8mq_usb_phy_power_off(usb_phy);
158 }
159
160 struct phy_ops imx8mq_usb_phy_ops = {
161         .init = imx8mq_usb_phy_init,
162         .power_on = imx8mq_usb_phy_power_on,
163         .power_off = imx8mq_usb_phy_power_off,
164         .exit = imx8mq_usb_phy_exit,
165 };
166
167 int imx8mq_usb_phy_probe(struct udevice *dev)
168 {
169         struct imx8mq_usb_phy *priv = dev_get_priv(dev);
170
171         priv->base = dev_read_addr_ptr(dev);
172
173         if (!priv->base)
174                 return -EINVAL;
175
176 #if CONFIG_IS_ENABLED(CLK)
177         int ret;
178
179         /* Assigned clock already set clock */
180         ret = clk_get_by_name(dev, "phy", &priv->phy_clk);
181         if (ret) {
182                 printf("Failed to get usb phy clock\n");
183                 return ret;
184         }
185 #endif
186
187         return 0;
188 }
189
190 U_BOOT_DRIVER(nxp_imx8mq_usb_phy) = {
191         .name = "nxp_imx8mq_usb_phy",
192         .id = UCLASS_PHY,
193         .of_match = imx8mq_usb_phy_of_match,
194         .probe = imx8mq_usb_phy_probe,
195         .ops = &imx8mq_usb_phy_ops,
196         .priv_auto      = sizeof(struct imx8mq_usb_phy),
197 };