| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | | - * Samsung EXYNOS5 SoC series USB DRD PHY driver |
|---|
| 3 | + * Samsung Exynos5 SoC series USB DRD PHY driver |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Phy provider for USB 3.0 DRD controller on Exynos5 SoC series |
|---|
| 5 | 6 | * |
|---|
| 6 | 7 | * Copyright (C) 2014 Samsung Electronics Co., Ltd. |
|---|
| 7 | 8 | * Author: Vivek Gautam <gautam.vivek@samsung.com> |
|---|
| 8 | | - * |
|---|
| 9 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 10 | | - * it under the terms of the GNU General Public License version 2 as |
|---|
| 11 | | - * published by the Free Software Foundation. |
|---|
| 12 | 9 | */ |
|---|
| 13 | 10 | |
|---|
| 14 | 11 | #include <linux/clk.h> |
|---|
| .. | .. |
|---|
| 19 | 16 | #include <linux/of.h> |
|---|
| 20 | 17 | #include <linux/of_address.h> |
|---|
| 21 | 18 | #include <linux/of_device.h> |
|---|
| 19 | +#include <linux/iopoll.h> |
|---|
| 22 | 20 | #include <linux/phy/phy.h> |
|---|
| 23 | 21 | #include <linux/platform_device.h> |
|---|
| 24 | 22 | #include <linux/mutex.h> |
|---|
| .. | .. |
|---|
| 36 | 34 | #define EXYNOS5_FSEL_24MHZ 0x5 |
|---|
| 37 | 35 | #define EXYNOS5_FSEL_50MHZ 0x7 |
|---|
| 38 | 36 | |
|---|
| 39 | | -/* EXYNOS5: USB 3.0 DRD PHY registers */ |
|---|
| 37 | +/* Exynos5: USB 3.0 DRD PHY registers */ |
|---|
| 40 | 38 | #define EXYNOS5_DRD_LINKSYSTEM 0x04 |
|---|
| 41 | 39 | |
|---|
| 42 | 40 | #define LINKSYSTEM_FLADJ_MASK (0x3f << 1) |
|---|
| .. | .. |
|---|
| 183 | 181 | * @utmiclk: clock for utmi+ phy |
|---|
| 184 | 182 | * @itpclk: clock for ITP generation |
|---|
| 185 | 183 | * @drv_data: pointer to SoC level driver data structure |
|---|
| 186 | | - * @phys[]: array for 'EXYNOS5_DRDPHYS_NUM' number of PHY |
|---|
| 184 | + * @phys: array for 'EXYNOS5_DRDPHYS_NUM' number of PHY |
|---|
| 187 | 185 | * instances each with its 'phy' and 'phy_cfg'. |
|---|
| 188 | 186 | * @extrefclk: frequency select settings when using 'separate |
|---|
| 189 | 187 | * reference clocks' for SS and HS operations |
|---|
| 190 | 188 | * @ref_clk: reference clock to PHY block from which PHY's |
|---|
| 191 | 189 | * operational clocks are derived |
|---|
| 192 | | - * vbus: VBUS regulator for phy |
|---|
| 193 | | - * vbus_boost: Boost regulator for VBUS present on few Exynos boards |
|---|
| 190 | + * @vbus: VBUS regulator for phy |
|---|
| 191 | + * @vbus_boost: Boost regulator for VBUS present on few Exynos boards |
|---|
| 194 | 192 | */ |
|---|
| 195 | 193 | struct exynos5_usbdrd_phy { |
|---|
| 196 | 194 | struct device *dev; |
|---|
| .. | .. |
|---|
| 559 | 557 | static int crport_handshake(struct exynos5_usbdrd_phy *phy_drd, |
|---|
| 560 | 558 | u32 val, u32 cmd) |
|---|
| 561 | 559 | { |
|---|
| 562 | | - u32 usec = 100; |
|---|
| 563 | 560 | unsigned int result; |
|---|
| 561 | + int err; |
|---|
| 564 | 562 | |
|---|
| 565 | 563 | writel(val | cmd, phy_drd->reg_phy + EXYNOS5_DRD_PHYREG0); |
|---|
| 566 | 564 | |
|---|
| 567 | | - do { |
|---|
| 568 | | - result = readl(phy_drd->reg_phy + EXYNOS5_DRD_PHYREG1); |
|---|
| 569 | | - if (result & PHYREG1_CR_ACK) |
|---|
| 570 | | - break; |
|---|
| 571 | | - |
|---|
| 572 | | - udelay(1); |
|---|
| 573 | | - } while (usec-- > 0); |
|---|
| 574 | | - |
|---|
| 575 | | - if (!usec) { |
|---|
| 576 | | - dev_err(phy_drd->dev, |
|---|
| 577 | | - "CRPORT handshake timeout1 (0x%08x)\n", val); |
|---|
| 578 | | - return -ETIME; |
|---|
| 565 | + err = readl_poll_timeout(phy_drd->reg_phy + EXYNOS5_DRD_PHYREG1, |
|---|
| 566 | + result, (result & PHYREG1_CR_ACK), 1, 100); |
|---|
| 567 | + if (err == -ETIMEDOUT) { |
|---|
| 568 | + dev_err(phy_drd->dev, "CRPORT handshake timeout1 (0x%08x)\n", val); |
|---|
| 569 | + return err; |
|---|
| 579 | 570 | } |
|---|
| 580 | | - |
|---|
| 581 | | - usec = 100; |
|---|
| 582 | 571 | |
|---|
| 583 | 572 | writel(val, phy_drd->reg_phy + EXYNOS5_DRD_PHYREG0); |
|---|
| 584 | 573 | |
|---|
| 585 | | - do { |
|---|
| 586 | | - result = readl(phy_drd->reg_phy + EXYNOS5_DRD_PHYREG1); |
|---|
| 587 | | - if (!(result & PHYREG1_CR_ACK)) |
|---|
| 588 | | - break; |
|---|
| 589 | | - |
|---|
| 590 | | - udelay(1); |
|---|
| 591 | | - } while (usec-- > 0); |
|---|
| 592 | | - |
|---|
| 593 | | - if (!usec) { |
|---|
| 594 | | - dev_err(phy_drd->dev, |
|---|
| 595 | | - "CRPORT handshake timeout2 (0x%08x)\n", val); |
|---|
| 596 | | - return -ETIME; |
|---|
| 574 | + err = readl_poll_timeout(phy_drd->reg_phy + EXYNOS5_DRD_PHYREG1, |
|---|
| 575 | + result, !(result & PHYREG1_CR_ACK), 1, 100); |
|---|
| 576 | + if (err == -ETIMEDOUT) { |
|---|
| 577 | + dev_err(phy_drd->dev, "CRPORT handshake timeout2 (0x%08x)\n", val); |
|---|
| 578 | + return err; |
|---|
| 597 | 579 | } |
|---|
| 598 | 580 | |
|---|
| 599 | 581 | return 0; |
|---|
| .. | .. |
|---|
| 958 | 940 | .driver = { |
|---|
| 959 | 941 | .of_match_table = exynos5_usbdrd_phy_of_match, |
|---|
| 960 | 942 | .name = "exynos5_usb3drd_phy", |
|---|
| 943 | + .suppress_bind_attrs = true, |
|---|
| 961 | 944 | } |
|---|
| 962 | 945 | }; |
|---|
| 963 | 946 | |
|---|
| 964 | 947 | module_platform_driver(exynos5_usb3drd_phy); |
|---|
| 965 | | -MODULE_DESCRIPTION("Samsung EXYNOS5 SoCs USB 3.0 DRD controller PHY driver"); |
|---|
| 948 | +MODULE_DESCRIPTION("Samsung Exynos5 SoCs USB 3.0 DRD controller PHY driver"); |
|---|
| 966 | 949 | MODULE_AUTHOR("Vivek Gautam <gautam.vivek@samsung.com>"); |
|---|
| 967 | 950 | MODULE_LICENSE("GPL v2"); |
|---|
| 968 | 951 | MODULE_ALIAS("platform:exynos5_usb3drd_phy"); |
|---|