| .. | .. |
|---|
| 17 | 17 | #include <linux/of_device.h> |
|---|
| 18 | 18 | #include <linux/regmap.h> |
|---|
| 19 | 19 | #include <linux/mfd/syscon.h> |
|---|
| 20 | +#include <linux/iopoll.h> |
|---|
| 20 | 21 | |
|---|
| 21 | 22 | #define DRIVER_NAME "mxs_phy" |
|---|
| 22 | 23 | |
|---|
| 24 | +/* Register Macro */ |
|---|
| 23 | 25 | #define HW_USBPHY_PWD 0x00 |
|---|
| 24 | 26 | #define HW_USBPHY_TX 0x10 |
|---|
| 25 | 27 | #define HW_USBPHY_CTRL 0x30 |
|---|
| .. | .. |
|---|
| 36 | 38 | #define GM_USBPHY_TX_TXCAL45DP(x) (((x) & 0xf) << 16) |
|---|
| 37 | 39 | #define GM_USBPHY_TX_TXCAL45DN(x) (((x) & 0xf) << 8) |
|---|
| 38 | 40 | #define GM_USBPHY_TX_D_CAL(x) (((x) & 0xf) << 0) |
|---|
| 41 | + |
|---|
| 42 | +/* imx7ulp */ |
|---|
| 43 | +#define HW_USBPHY_PLL_SIC 0xa0 |
|---|
| 44 | +#define HW_USBPHY_PLL_SIC_SET 0xa4 |
|---|
| 45 | +#define HW_USBPHY_PLL_SIC_CLR 0xa8 |
|---|
| 39 | 46 | |
|---|
| 40 | 47 | #define BM_USBPHY_CTRL_SFTRST BIT(31) |
|---|
| 41 | 48 | #define BM_USBPHY_CTRL_CLKGATE BIT(30) |
|---|
| .. | .. |
|---|
| 55 | 62 | #define BM_USBPHY_IP_FIX (BIT(17) | BIT(18)) |
|---|
| 56 | 63 | |
|---|
| 57 | 64 | #define BM_USBPHY_DEBUG_CLKGATE BIT(30) |
|---|
| 65 | +/* imx7ulp */ |
|---|
| 66 | +#define BM_USBPHY_PLL_LOCK BIT(31) |
|---|
| 67 | +#define BM_USBPHY_PLL_REG_ENABLE BIT(21) |
|---|
| 68 | +#define BM_USBPHY_PLL_BYPASS BIT(16) |
|---|
| 69 | +#define BM_USBPHY_PLL_POWER BIT(12) |
|---|
| 70 | +#define BM_USBPHY_PLL_EN_USB_CLKS BIT(6) |
|---|
| 58 | 71 | |
|---|
| 59 | 72 | /* Anatop Registers */ |
|---|
| 60 | 73 | #define ANADIG_ANA_MISC0 0x150 |
|---|
| .. | .. |
|---|
| 63 | 76 | |
|---|
| 64 | 77 | #define ANADIG_USB1_CHRG_DETECT_SET 0x1b4 |
|---|
| 65 | 78 | #define ANADIG_USB1_CHRG_DETECT_CLR 0x1b8 |
|---|
| 79 | +#define ANADIG_USB2_CHRG_DETECT_SET 0x214 |
|---|
| 66 | 80 | #define ANADIG_USB1_CHRG_DETECT_EN_B BIT(20) |
|---|
| 67 | 81 | #define ANADIG_USB1_CHRG_DETECT_CHK_CHRG_B BIT(19) |
|---|
| 68 | 82 | #define ANADIG_USB1_CHRG_DETECT_CHK_CONTACT BIT(18) |
|---|
| .. | .. |
|---|
| 167 | 181 | .flags = MXS_PHY_DISCONNECT_LINE_WITHOUT_VBUS, |
|---|
| 168 | 182 | }; |
|---|
| 169 | 183 | |
|---|
| 184 | +static const struct mxs_phy_data imx7ulp_phy_data = { |
|---|
| 185 | +}; |
|---|
| 186 | + |
|---|
| 170 | 187 | static const struct of_device_id mxs_phy_dt_ids[] = { |
|---|
| 171 | 188 | { .compatible = "fsl,imx6sx-usbphy", .data = &imx6sx_phy_data, }, |
|---|
| 172 | 189 | { .compatible = "fsl,imx6sl-usbphy", .data = &imx6sl_phy_data, }, |
|---|
| .. | .. |
|---|
| 174 | 191 | { .compatible = "fsl,imx23-usbphy", .data = &imx23_phy_data, }, |
|---|
| 175 | 192 | { .compatible = "fsl,vf610-usbphy", .data = &vf610_phy_data, }, |
|---|
| 176 | 193 | { .compatible = "fsl,imx6ul-usbphy", .data = &imx6ul_phy_data, }, |
|---|
| 194 | + { .compatible = "fsl,imx7ulp-usbphy", .data = &imx7ulp_phy_data, }, |
|---|
| 177 | 195 | { /* sentinel */ } |
|---|
| 178 | 196 | }; |
|---|
| 179 | 197 | MODULE_DEVICE_TABLE(of, mxs_phy_dt_ids); |
|---|
| .. | .. |
|---|
| 196 | 214 | static inline bool is_imx6sl_phy(struct mxs_phy *mxs_phy) |
|---|
| 197 | 215 | { |
|---|
| 198 | 216 | return mxs_phy->data == &imx6sl_phy_data; |
|---|
| 217 | +} |
|---|
| 218 | + |
|---|
| 219 | +static inline bool is_imx7ulp_phy(struct mxs_phy *mxs_phy) |
|---|
| 220 | +{ |
|---|
| 221 | + return mxs_phy->data == &imx7ulp_phy_data; |
|---|
| 199 | 222 | } |
|---|
| 200 | 223 | |
|---|
| 201 | 224 | /* |
|---|
| .. | .. |
|---|
| 221 | 244 | } |
|---|
| 222 | 245 | } |
|---|
| 223 | 246 | |
|---|
| 247 | +static int mxs_phy_pll_enable(void __iomem *base, bool enable) |
|---|
| 248 | +{ |
|---|
| 249 | + int ret = 0; |
|---|
| 250 | + |
|---|
| 251 | + if (enable) { |
|---|
| 252 | + u32 value; |
|---|
| 253 | + |
|---|
| 254 | + writel(BM_USBPHY_PLL_REG_ENABLE, base + HW_USBPHY_PLL_SIC_SET); |
|---|
| 255 | + writel(BM_USBPHY_PLL_BYPASS, base + HW_USBPHY_PLL_SIC_CLR); |
|---|
| 256 | + writel(BM_USBPHY_PLL_POWER, base + HW_USBPHY_PLL_SIC_SET); |
|---|
| 257 | + ret = readl_poll_timeout(base + HW_USBPHY_PLL_SIC, |
|---|
| 258 | + value, (value & BM_USBPHY_PLL_LOCK) != 0, |
|---|
| 259 | + 100, 10000); |
|---|
| 260 | + if (ret) |
|---|
| 261 | + return ret; |
|---|
| 262 | + |
|---|
| 263 | + writel(BM_USBPHY_PLL_EN_USB_CLKS, base + |
|---|
| 264 | + HW_USBPHY_PLL_SIC_SET); |
|---|
| 265 | + } else { |
|---|
| 266 | + writel(BM_USBPHY_PLL_EN_USB_CLKS, base + |
|---|
| 267 | + HW_USBPHY_PLL_SIC_CLR); |
|---|
| 268 | + writel(BM_USBPHY_PLL_POWER, base + HW_USBPHY_PLL_SIC_CLR); |
|---|
| 269 | + writel(BM_USBPHY_PLL_BYPASS, base + HW_USBPHY_PLL_SIC_SET); |
|---|
| 270 | + writel(BM_USBPHY_PLL_REG_ENABLE, base + HW_USBPHY_PLL_SIC_CLR); |
|---|
| 271 | + } |
|---|
| 272 | + |
|---|
| 273 | + return ret; |
|---|
| 274 | +} |
|---|
| 275 | + |
|---|
| 224 | 276 | static int mxs_phy_hw_init(struct mxs_phy *mxs_phy) |
|---|
| 225 | 277 | { |
|---|
| 226 | 278 | int ret; |
|---|
| 227 | 279 | void __iomem *base = mxs_phy->phy.io_priv; |
|---|
| 228 | 280 | |
|---|
| 281 | + if (is_imx7ulp_phy(mxs_phy)) { |
|---|
| 282 | + ret = mxs_phy_pll_enable(base, true); |
|---|
| 283 | + if (ret) |
|---|
| 284 | + return ret; |
|---|
| 285 | + } |
|---|
| 286 | + |
|---|
| 229 | 287 | ret = stmp_reset_block(base + HW_USBPHY_CTRL); |
|---|
| 230 | 288 | if (ret) |
|---|
| 231 | | - return ret; |
|---|
| 289 | + goto disable_pll; |
|---|
| 232 | 290 | |
|---|
| 233 | 291 | /* Power up the PHY */ |
|---|
| 234 | 292 | writel(0, base + HW_USBPHY_PWD); |
|---|
| .. | .. |
|---|
| 250 | 308 | if (mxs_phy->data->flags & MXS_PHY_NEED_IP_FIX) |
|---|
| 251 | 309 | writel(BM_USBPHY_IP_FIX, base + HW_USBPHY_IP_SET); |
|---|
| 252 | 310 | |
|---|
| 311 | + if (mxs_phy->regmap_anatop) { |
|---|
| 312 | + unsigned int reg = mxs_phy->port_id ? |
|---|
| 313 | + ANADIG_USB1_CHRG_DETECT_SET : |
|---|
| 314 | + ANADIG_USB2_CHRG_DETECT_SET; |
|---|
| 315 | + /* |
|---|
| 316 | + * The external charger detector needs to be disabled, |
|---|
| 317 | + * or the signal at DP will be poor |
|---|
| 318 | + */ |
|---|
| 319 | + regmap_write(mxs_phy->regmap_anatop, reg, |
|---|
| 320 | + ANADIG_USB1_CHRG_DETECT_EN_B | |
|---|
| 321 | + ANADIG_USB1_CHRG_DETECT_CHK_CHRG_B); |
|---|
| 322 | + } |
|---|
| 323 | + |
|---|
| 253 | 324 | mxs_phy_tx_init(mxs_phy); |
|---|
| 254 | 325 | |
|---|
| 255 | 326 | return 0; |
|---|
| 327 | + |
|---|
| 328 | +disable_pll: |
|---|
| 329 | + if (is_imx7ulp_phy(mxs_phy)) |
|---|
| 330 | + mxs_phy_pll_enable(base, false); |
|---|
| 331 | + return ret; |
|---|
| 256 | 332 | } |
|---|
| 257 | 333 | |
|---|
| 258 | 334 | /* Return true if the vbus is there */ |
|---|
| .. | .. |
|---|
| 312 | 388 | |
|---|
| 313 | 389 | static bool mxs_phy_is_otg_host(struct mxs_phy *mxs_phy) |
|---|
| 314 | 390 | { |
|---|
| 315 | | - void __iomem *base = mxs_phy->phy.io_priv; |
|---|
| 316 | | - u32 phyctrl = readl(base + HW_USBPHY_CTRL); |
|---|
| 317 | | - |
|---|
| 318 | | - if (IS_ENABLED(CONFIG_USB_OTG) && |
|---|
| 319 | | - !(phyctrl & BM_USBPHY_CTRL_OTG_ID_VALUE)) |
|---|
| 320 | | - return true; |
|---|
| 321 | | - |
|---|
| 322 | | - return false; |
|---|
| 391 | + return IS_ENABLED(CONFIG_USB_OTG) && |
|---|
| 392 | + mxs_phy->phy.last_event == USB_EVENT_ID; |
|---|
| 323 | 393 | } |
|---|
| 324 | 394 | |
|---|
| 325 | 395 | static void mxs_phy_disconnect_line(struct mxs_phy *mxs_phy, bool on) |
|---|
| .. | .. |
|---|
| 373 | 443 | |
|---|
| 374 | 444 | writel(BM_USBPHY_CTRL_CLKGATE, |
|---|
| 375 | 445 | phy->io_priv + HW_USBPHY_CTRL_SET); |
|---|
| 446 | + |
|---|
| 447 | + if (is_imx7ulp_phy(mxs_phy)) |
|---|
| 448 | + mxs_phy_pll_enable(phy->io_priv, false); |
|---|
| 376 | 449 | |
|---|
| 377 | 450 | clk_disable_unprepare(mxs_phy->clk); |
|---|
| 378 | 451 | } |
|---|
| .. | .. |
|---|
| 563 | 636 | regmap_read(regmap, ANADIG_USB1_CHRG_DET_STAT, &val); |
|---|
| 564 | 637 | if (!(val & ANADIG_USB1_CHRG_DET_STAT_CHRG_DETECTED)) { |
|---|
| 565 | 638 | chgr_type = SDP_TYPE; |
|---|
| 566 | | - dev_dbg(x->phy.dev, "It is a stardard downstream port\n"); |
|---|
| 639 | + dev_dbg(x->phy.dev, "It is a standard downstream port\n"); |
|---|
| 567 | 640 | } |
|---|
| 568 | 641 | |
|---|
| 569 | 642 | /* Disable charger detector */ |
|---|
| .. | .. |
|---|
| 631 | 704 | |
|---|
| 632 | 705 | static int mxs_phy_probe(struct platform_device *pdev) |
|---|
| 633 | 706 | { |
|---|
| 634 | | - struct resource *res; |
|---|
| 635 | 707 | void __iomem *base; |
|---|
| 636 | 708 | struct clk *clk; |
|---|
| 637 | 709 | struct mxs_phy *mxs_phy; |
|---|
| .. | .. |
|---|
| 644 | 716 | if (!of_id) |
|---|
| 645 | 717 | return -ENODEV; |
|---|
| 646 | 718 | |
|---|
| 647 | | - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
|---|
| 648 | | - base = devm_ioremap_resource(&pdev->dev, res); |
|---|
| 719 | + base = devm_platform_ioremap_resource(pdev, 0); |
|---|
| 649 | 720 | if (IS_ERR(base)) |
|---|
| 650 | 721 | return PTR_ERR(base); |
|---|
| 651 | 722 | |
|---|