diff options
Diffstat (limited to 'drivers/phy')
27 files changed, 2202 insertions, 133 deletions
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index e8f8a2d165d1..0dd742719154 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig | |||
@@ -15,6 +15,13 @@ config GENERIC_PHY | |||
15 | phy users can obtain reference to the PHY. All the users of this | 15 | phy users can obtain reference to the PHY. All the users of this |
16 | framework should select this config. | 16 | framework should select this config. |
17 | 17 | ||
18 | config PHY_BERLIN_SATA | ||
19 | tristate "Marvell Berlin SATA PHY driver" | ||
20 | depends on ARCH_BERLIN && HAS_IOMEM && OF | ||
21 | select GENERIC_PHY | ||
22 | help | ||
23 | Enable this to support the SATA PHY on Marvell Berlin SoCs. | ||
24 | |||
18 | config PHY_EXYNOS_MIPI_VIDEO | 25 | config PHY_EXYNOS_MIPI_VIDEO |
19 | tristate "S5P/EXYNOS SoC series MIPI CSI-2/DSI PHY driver" | 26 | tristate "S5P/EXYNOS SoC series MIPI CSI-2/DSI PHY driver" |
20 | depends on HAS_IOMEM | 27 | depends on HAS_IOMEM |
@@ -27,10 +34,20 @@ config PHY_EXYNOS_MIPI_VIDEO | |||
27 | 34 | ||
28 | config PHY_MVEBU_SATA | 35 | config PHY_MVEBU_SATA |
29 | def_bool y | 36 | def_bool y |
30 | depends on ARCH_KIRKWOOD || ARCH_DOVE || MACH_DOVE || MACH_KIRKWOOD | 37 | depends on ARCH_DOVE || MACH_DOVE || MACH_KIRKWOOD |
31 | depends on OF | 38 | depends on OF |
32 | select GENERIC_PHY | 39 | select GENERIC_PHY |
33 | 40 | ||
41 | config PHY_MIPHY365X | ||
42 | tristate "STMicroelectronics MIPHY365X PHY driver for STiH41x series" | ||
43 | depends on ARCH_STI | ||
44 | depends on GENERIC_PHY | ||
45 | depends on HAS_IOMEM | ||
46 | depends on OF | ||
47 | help | ||
48 | Enable this to support the miphy transceiver (for SATA/PCIE) | ||
49 | that is part of STMicroelectronics STiH41x SoC series. | ||
50 | |||
34 | config OMAP_CONTROL_PHY | 51 | config OMAP_CONTROL_PHY |
35 | tristate "OMAP CONTROL PHY Driver" | 52 | tristate "OMAP CONTROL PHY Driver" |
36 | depends on ARCH_OMAP2PLUS || COMPILE_TEST | 53 | depends on ARCH_OMAP2PLUS || COMPILE_TEST |
@@ -109,9 +126,18 @@ config PHY_EXYNOS5250_SATA | |||
109 | SATA 3.0 Gb/s, SATA 6.0 Gb/s speeds. It supports one SATA host | 126 | SATA 3.0 Gb/s, SATA 6.0 Gb/s speeds. It supports one SATA host |
110 | port to accept one SATA device. | 127 | port to accept one SATA device. |
111 | 128 | ||
129 | config PHY_HIX5HD2_SATA | ||
130 | tristate "HIX5HD2 SATA PHY Driver" | ||
131 | depends on ARCH_HIX5HD2 && OF && HAS_IOMEM | ||
132 | select GENERIC_PHY | ||
133 | select MFD_SYSCON | ||
134 | help | ||
135 | Support for SATA PHY on Hisilicon hix5hd2 Soc. | ||
136 | |||
112 | config PHY_SUN4I_USB | 137 | config PHY_SUN4I_USB |
113 | tristate "Allwinner sunxi SoC USB PHY driver" | 138 | tristate "Allwinner sunxi SoC USB PHY driver" |
114 | depends on ARCH_SUNXI && HAS_IOMEM && OF | 139 | depends on ARCH_SUNXI && HAS_IOMEM && OF |
140 | depends on RESET_CONTROLLER | ||
115 | select GENERIC_PHY | 141 | select GENERIC_PHY |
116 | help | 142 | help |
117 | Enable this to support the transceiver that is part of Allwinner | 143 | Enable this to support the transceiver that is part of Allwinner |
@@ -122,61 +148,68 @@ config PHY_SUN4I_USB | |||
122 | 148 | ||
123 | config PHY_SAMSUNG_USB2 | 149 | config PHY_SAMSUNG_USB2 |
124 | tristate "Samsung USB 2.0 PHY driver" | 150 | tristate "Samsung USB 2.0 PHY driver" |
151 | depends on HAS_IOMEM | ||
152 | depends on USB_EHCI_EXYNOS || USB_OHCI_EXYNOS || USB_DWC2 | ||
125 | select GENERIC_PHY | 153 | select GENERIC_PHY |
126 | select MFD_SYSCON | 154 | select MFD_SYSCON |
155 | default ARCH_EXYNOS | ||
127 | help | 156 | help |
128 | Enable this to support the Samsung USB 2.0 PHY driver for Samsung | 157 | Enable this to support the Samsung USB 2.0 PHY driver for Samsung |
129 | SoCs. This driver provides the interface for USB 2.0 PHY. Support for | 158 | SoCs. This driver provides the interface for USB 2.0 PHY. Support |
130 | particular SoCs has to be enabled in addition to this driver. Number | 159 | for particular PHYs will be enabled based on the SoC type in addition |
131 | and type of supported phys depends on the SoC. | 160 | to this driver. |
132 | 161 | ||
133 | config PHY_EXYNOS4210_USB2 | 162 | config PHY_S5PV210_USB2 |
134 | bool "Support for Exynos 4210" | 163 | bool "Support for S5PV210" |
135 | depends on PHY_SAMSUNG_USB2 | 164 | depends on PHY_SAMSUNG_USB2 |
136 | depends on CPU_EXYNOS4210 | 165 | depends on ARCH_S5PV210 |
137 | help | 166 | help |
138 | Enable USB PHY support for Exynos 4210. This option requires that | 167 | Enable USB PHY support for S5PV210. This option requires that Samsung |
139 | Samsung USB 2.0 PHY driver is enabled and means that support for this | 168 | USB 2.0 PHY driver is enabled and means that support for this |
140 | particular SoC is compiled in the driver. In case of Exynos 4210 four | 169 | particular SoC is compiled in the driver. In case of S5PV210 two phys |
141 | phys are available - device, host, HSIC0 and HSIC1. | 170 | are available - device and host. |
171 | |||
172 | config PHY_EXYNOS4210_USB2 | ||
173 | bool | ||
174 | depends on PHY_SAMSUNG_USB2 | ||
175 | default CPU_EXYNOS4210 | ||
142 | 176 | ||
143 | config PHY_EXYNOS4X12_USB2 | 177 | config PHY_EXYNOS4X12_USB2 |
144 | bool "Support for Exynos 4x12" | 178 | bool |
145 | depends on PHY_SAMSUNG_USB2 | 179 | depends on PHY_SAMSUNG_USB2 |
146 | depends on (SOC_EXYNOS4212 || SOC_EXYNOS4412) | 180 | default SOC_EXYNOS3250 || SOC_EXYNOS4212 || SOC_EXYNOS4412 |
147 | help | ||
148 | Enable USB PHY support for Exynos 4x12. This option requires that | ||
149 | Samsung USB 2.0 PHY driver is enabled and means that support for this | ||
150 | particular SoC is compiled in the driver. In case of Exynos 4x12 four | ||
151 | phys are available - device, host, HSIC0 and HSIC1. | ||
152 | 181 | ||
153 | config PHY_EXYNOS5250_USB2 | 182 | config PHY_EXYNOS5250_USB2 |
154 | bool "Support for Exynos 5250" | 183 | bool |
155 | depends on PHY_SAMSUNG_USB2 | 184 | depends on PHY_SAMSUNG_USB2 |
156 | depends on SOC_EXYNOS5250 | 185 | default SOC_EXYNOS5250 || SOC_EXYNOS5420 |
157 | help | ||
158 | Enable USB PHY support for Exynos 5250. This option requires that | ||
159 | Samsung USB 2.0 PHY driver is enabled and means that support for this | ||
160 | particular SoC is compiled in the driver. In case of Exynos 5250 four | ||
161 | phys are available - device, host, HSIC0 and HSIC. | ||
162 | 186 | ||
163 | config PHY_EXYNOS5_USBDRD | 187 | config PHY_EXYNOS5_USBDRD |
164 | tristate "Exynos5 SoC series USB DRD PHY driver" | 188 | tristate "Exynos5 SoC series USB DRD PHY driver" |
165 | depends on ARCH_EXYNOS5 && OF | 189 | depends on ARCH_EXYNOS5 && OF |
166 | depends on HAS_IOMEM | 190 | depends on HAS_IOMEM |
191 | depends on USB_DWC3_EXYNOS | ||
167 | select GENERIC_PHY | 192 | select GENERIC_PHY |
168 | select MFD_SYSCON | 193 | select MFD_SYSCON |
194 | default y | ||
169 | help | 195 | help |
170 | Enable USB DRD PHY support for Exynos 5 SoC series. | 196 | Enable USB DRD PHY support for Exynos 5 SoC series. |
171 | This driver provides PHY interface for USB 3.0 DRD controller | 197 | This driver provides PHY interface for USB 3.0 DRD controller |
172 | present on Exynos5 SoC series. | 198 | present on Exynos5 SoC series. |
173 | 199 | ||
174 | config PHY_XGENE | 200 | config PHY_QCOM_APQ8064_SATA |
175 | tristate "APM X-Gene 15Gbps PHY support" | 201 | tristate "Qualcomm APQ8064 SATA SerDes/PHY driver" |
176 | depends on HAS_IOMEM && OF && (ARM64 || COMPILE_TEST) | 202 | depends on ARCH_QCOM |
203 | depends on HAS_IOMEM | ||
204 | depends on OF | ||
205 | select GENERIC_PHY | ||
206 | |||
207 | config PHY_QCOM_IPQ806X_SATA | ||
208 | tristate "Qualcomm IPQ806x SATA SerDes/PHY driver" | ||
209 | depends on ARCH_QCOM | ||
210 | depends on HAS_IOMEM | ||
211 | depends on OF | ||
177 | select GENERIC_PHY | 212 | select GENERIC_PHY |
178 | help | ||
179 | This option enables support for APM X-Gene SoC multi-purpose PHY. | ||
180 | 213 | ||
181 | config PHY_ST_SPEAR1310_MIPHY | 214 | config PHY_ST_SPEAR1310_MIPHY |
182 | tristate "ST SPEAR1310-MIPHY driver" | 215 | tristate "ST SPEAR1310-MIPHY driver" |
@@ -190,4 +223,11 @@ config PHY_ST_SPEAR1340_MIPHY | |||
190 | help | 223 | help |
191 | Support for ST SPEAr1340 MIPHY which can be used for PCIe and SATA. | 224 | Support for ST SPEAr1340 MIPHY which can be used for PCIe and SATA. |
192 | 225 | ||
226 | config PHY_XGENE | ||
227 | tristate "APM X-Gene 15Gbps PHY support" | ||
228 | depends on HAS_IOMEM && OF && (ARM64 || COMPILE_TEST) | ||
229 | select GENERIC_PHY | ||
230 | help | ||
231 | This option enables support for APM X-Gene SoC multi-purpose PHY. | ||
232 | |||
193 | endmenu | 233 | endmenu |
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index d39609bb38de..95c69ed5ed45 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile | |||
@@ -3,22 +3,28 @@ | |||
3 | # | 3 | # |
4 | 4 | ||
5 | obj-$(CONFIG_GENERIC_PHY) += phy-core.o | 5 | obj-$(CONFIG_GENERIC_PHY) += phy-core.o |
6 | obj-$(CONFIG_PHY_BERLIN_SATA) += phy-berlin-sata.o | ||
6 | obj-$(CONFIG_BCM_KONA_USB2_PHY) += phy-bcm-kona-usb2.o | 7 | obj-$(CONFIG_BCM_KONA_USB2_PHY) += phy-bcm-kona-usb2.o |
7 | obj-$(CONFIG_PHY_EXYNOS_DP_VIDEO) += phy-exynos-dp-video.o | 8 | obj-$(CONFIG_PHY_EXYNOS_DP_VIDEO) += phy-exynos-dp-video.o |
8 | obj-$(CONFIG_PHY_EXYNOS_MIPI_VIDEO) += phy-exynos-mipi-video.o | 9 | obj-$(CONFIG_PHY_EXYNOS_MIPI_VIDEO) += phy-exynos-mipi-video.o |
9 | obj-$(CONFIG_PHY_MVEBU_SATA) += phy-mvebu-sata.o | 10 | obj-$(CONFIG_PHY_MVEBU_SATA) += phy-mvebu-sata.o |
11 | obj-$(CONFIG_PHY_MIPHY365X) += phy-miphy365x.o | ||
10 | obj-$(CONFIG_OMAP_CONTROL_PHY) += phy-omap-control.o | 12 | obj-$(CONFIG_OMAP_CONTROL_PHY) += phy-omap-control.o |
11 | obj-$(CONFIG_OMAP_USB2) += phy-omap-usb2.o | 13 | obj-$(CONFIG_OMAP_USB2) += phy-omap-usb2.o |
12 | obj-$(CONFIG_TI_PIPE3) += phy-ti-pipe3.o | 14 | obj-$(CONFIG_TI_PIPE3) += phy-ti-pipe3.o |
13 | obj-$(CONFIG_TWL4030_USB) += phy-twl4030-usb.o | 15 | obj-$(CONFIG_TWL4030_USB) += phy-twl4030-usb.o |
14 | obj-$(CONFIG_PHY_EXYNOS5250_SATA) += phy-exynos5250-sata.o | 16 | obj-$(CONFIG_PHY_EXYNOS5250_SATA) += phy-exynos5250-sata.o |
17 | obj-$(CONFIG_PHY_HIX5HD2_SATA) += phy-hix5hd2-sata.o | ||
15 | obj-$(CONFIG_PHY_SUN4I_USB) += phy-sun4i-usb.o | 18 | obj-$(CONFIG_PHY_SUN4I_USB) += phy-sun4i-usb.o |
16 | obj-$(CONFIG_PHY_SAMSUNG_USB2) += phy-exynos-usb2.o | 19 | obj-$(CONFIG_PHY_SAMSUNG_USB2) += phy-exynos-usb2.o |
17 | phy-exynos-usb2-y += phy-samsung-usb2.o | 20 | phy-exynos-usb2-y += phy-samsung-usb2.o |
18 | phy-exynos-usb2-$(CONFIG_PHY_EXYNOS4210_USB2) += phy-exynos4210-usb2.o | 21 | phy-exynos-usb2-$(CONFIG_PHY_EXYNOS4210_USB2) += phy-exynos4210-usb2.o |
19 | phy-exynos-usb2-$(CONFIG_PHY_EXYNOS4X12_USB2) += phy-exynos4x12-usb2.o | 22 | phy-exynos-usb2-$(CONFIG_PHY_EXYNOS4X12_USB2) += phy-exynos4x12-usb2.o |
20 | phy-exynos-usb2-$(CONFIG_PHY_EXYNOS5250_USB2) += phy-exynos5250-usb2.o | 23 | phy-exynos-usb2-$(CONFIG_PHY_EXYNOS5250_USB2) += phy-exynos5250-usb2.o |
24 | phy-exynos-usb2-$(CONFIG_PHY_S5PV210_USB2) += phy-s5pv210-usb2.o | ||
21 | obj-$(CONFIG_PHY_EXYNOS5_USBDRD) += phy-exynos5-usbdrd.o | 25 | obj-$(CONFIG_PHY_EXYNOS5_USBDRD) += phy-exynos5-usbdrd.o |
22 | obj-$(CONFIG_PHY_XGENE) += phy-xgene.o | 26 | obj-$(CONFIG_PHY_QCOM_APQ8064_SATA) += phy-qcom-apq8064-sata.o |
27 | obj-$(CONFIG_PHY_QCOM_IPQ806X_SATA) += phy-qcom-ipq806x-sata.o | ||
23 | obj-$(CONFIG_PHY_ST_SPEAR1310_MIPHY) += phy-spear1310-miphy.o | 28 | obj-$(CONFIG_PHY_ST_SPEAR1310_MIPHY) += phy-spear1310-miphy.o |
24 | obj-$(CONFIG_PHY_ST_SPEAR1340_MIPHY) += phy-spear1340-miphy.o | 29 | obj-$(CONFIG_PHY_ST_SPEAR1340_MIPHY) += phy-spear1340-miphy.o |
30 | obj-$(CONFIG_PHY_XGENE) += phy-xgene.o | ||
diff --git a/drivers/phy/phy-bcm-kona-usb2.c b/drivers/phy/phy-bcm-kona-usb2.c index e94f5a6a5645..894fe74c1e44 100644 --- a/drivers/phy/phy-bcm-kona-usb2.c +++ b/drivers/phy/phy-bcm-kona-usb2.c | |||
@@ -117,7 +117,7 @@ static int bcm_kona_usb2_probe(struct platform_device *pdev) | |||
117 | 117 | ||
118 | platform_set_drvdata(pdev, phy); | 118 | platform_set_drvdata(pdev, phy); |
119 | 119 | ||
120 | gphy = devm_phy_create(dev, &ops, NULL); | 120 | gphy = devm_phy_create(dev, NULL, &ops, NULL); |
121 | if (IS_ERR(gphy)) | 121 | if (IS_ERR(gphy)) |
122 | return PTR_ERR(gphy); | 122 | return PTR_ERR(gphy); |
123 | 123 | ||
diff --git a/drivers/phy/phy-berlin-sata.c b/drivers/phy/phy-berlin-sata.c new file mode 100644 index 000000000000..5c3a0424aeb4 --- /dev/null +++ b/drivers/phy/phy-berlin-sata.c | |||
@@ -0,0 +1,284 @@ | |||
1 | /* | ||
2 | * Marvell Berlin SATA PHY driver | ||
3 | * | ||
4 | * Copyright (C) 2014 Marvell Technology Group Ltd. | ||
5 | * | ||
6 | * Antoine Ténart <antoine.tenart@free-electrons.com> | ||
7 | * | ||
8 | * This file is licensed under the terms of the GNU General Public | ||
9 | * License version 2. This program is licensed "as is" without any | ||
10 | * warranty of any kind, whether express or implied. | ||
11 | */ | ||
12 | |||
13 | #include <linux/clk.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/phy/phy.h> | ||
16 | #include <linux/io.h> | ||
17 | #include <linux/platform_device.h> | ||
18 | |||
19 | #define HOST_VSA_ADDR 0x0 | ||
20 | #define HOST_VSA_DATA 0x4 | ||
21 | #define PORT_SCR_CTL 0x2c | ||
22 | #define PORT_VSR_ADDR 0x78 | ||
23 | #define PORT_VSR_DATA 0x7c | ||
24 | |||
25 | #define CONTROL_REGISTER 0x0 | ||
26 | #define MBUS_SIZE_CONTROL 0x4 | ||
27 | |||
28 | #define POWER_DOWN_PHY0 BIT(6) | ||
29 | #define POWER_DOWN_PHY1 BIT(14) | ||
30 | #define MBUS_WRITE_REQUEST_SIZE_128 (BIT(2) << 16) | ||
31 | #define MBUS_READ_REQUEST_SIZE_128 (BIT(2) << 19) | ||
32 | |||
33 | #define PHY_BASE 0x200 | ||
34 | |||
35 | /* register 0x01 */ | ||
36 | #define REF_FREF_SEL_25 BIT(0) | ||
37 | #define PHY_MODE_SATA (0x0 << 5) | ||
38 | |||
39 | /* register 0x02 */ | ||
40 | #define USE_MAX_PLL_RATE BIT(12) | ||
41 | |||
42 | /* register 0x23 */ | ||
43 | #define DATA_BIT_WIDTH_10 (0x0 << 10) | ||
44 | #define DATA_BIT_WIDTH_20 (0x1 << 10) | ||
45 | #define DATA_BIT_WIDTH_40 (0x2 << 10) | ||
46 | |||
47 | /* register 0x25 */ | ||
48 | #define PHY_GEN_MAX_1_5 (0x0 << 10) | ||
49 | #define PHY_GEN_MAX_3_0 (0x1 << 10) | ||
50 | #define PHY_GEN_MAX_6_0 (0x2 << 10) | ||
51 | |||
52 | struct phy_berlin_desc { | ||
53 | struct phy *phy; | ||
54 | u32 power_bit; | ||
55 | unsigned index; | ||
56 | }; | ||
57 | |||
58 | struct phy_berlin_priv { | ||
59 | void __iomem *base; | ||
60 | spinlock_t lock; | ||
61 | struct clk *clk; | ||
62 | struct phy_berlin_desc **phys; | ||
63 | unsigned nphys; | ||
64 | }; | ||
65 | |||
66 | static inline void phy_berlin_sata_reg_setbits(void __iomem *ctrl_reg, u32 reg, | ||
67 | u32 mask, u32 val) | ||
68 | { | ||
69 | u32 regval; | ||
70 | |||
71 | /* select register */ | ||
72 | writel(PHY_BASE + reg, ctrl_reg + PORT_VSR_ADDR); | ||
73 | |||
74 | /* set bits */ | ||
75 | regval = readl(ctrl_reg + PORT_VSR_DATA); | ||
76 | regval &= ~mask; | ||
77 | regval |= val; | ||
78 | writel(regval, ctrl_reg + PORT_VSR_DATA); | ||
79 | } | ||
80 | |||
81 | static int phy_berlin_sata_power_on(struct phy *phy) | ||
82 | { | ||
83 | struct phy_berlin_desc *desc = phy_get_drvdata(phy); | ||
84 | struct phy_berlin_priv *priv = dev_get_drvdata(phy->dev.parent); | ||
85 | void __iomem *ctrl_reg = priv->base + 0x60 + (desc->index * 0x80); | ||
86 | int ret = 0; | ||
87 | u32 regval; | ||
88 | |||
89 | clk_prepare_enable(priv->clk); | ||
90 | |||
91 | spin_lock(&priv->lock); | ||
92 | |||
93 | /* Power on PHY */ | ||
94 | writel(CONTROL_REGISTER, priv->base + HOST_VSA_ADDR); | ||
95 | regval = readl(priv->base + HOST_VSA_DATA); | ||
96 | regval &= ~desc->power_bit; | ||
97 | writel(regval, priv->base + HOST_VSA_DATA); | ||
98 | |||
99 | /* Configure MBus */ | ||
100 | writel(MBUS_SIZE_CONTROL, priv->base + HOST_VSA_ADDR); | ||
101 | regval = readl(priv->base + HOST_VSA_DATA); | ||
102 | regval |= MBUS_WRITE_REQUEST_SIZE_128 | MBUS_READ_REQUEST_SIZE_128; | ||
103 | writel(regval, priv->base + HOST_VSA_DATA); | ||
104 | |||
105 | /* set PHY mode and ref freq to 25 MHz */ | ||
106 | phy_berlin_sata_reg_setbits(ctrl_reg, 0x1, 0xff, | ||
107 | REF_FREF_SEL_25 | PHY_MODE_SATA); | ||
108 | |||
109 | /* set PHY up to 6 Gbps */ | ||
110 | phy_berlin_sata_reg_setbits(ctrl_reg, 0x25, 0xc00, PHY_GEN_MAX_6_0); | ||
111 | |||
112 | /* set 40 bits width */ | ||
113 | phy_berlin_sata_reg_setbits(ctrl_reg, 0x23, 0xc00, DATA_BIT_WIDTH_40); | ||
114 | |||
115 | /* use max pll rate */ | ||
116 | phy_berlin_sata_reg_setbits(ctrl_reg, 0x2, 0x0, USE_MAX_PLL_RATE); | ||
117 | |||
118 | /* set Gen3 controller speed */ | ||
119 | regval = readl(ctrl_reg + PORT_SCR_CTL); | ||
120 | regval &= ~GENMASK(7, 4); | ||
121 | regval |= 0x30; | ||
122 | writel(regval, ctrl_reg + PORT_SCR_CTL); | ||
123 | |||
124 | spin_unlock(&priv->lock); | ||
125 | |||
126 | clk_disable_unprepare(priv->clk); | ||
127 | |||
128 | return ret; | ||
129 | } | ||
130 | |||
131 | static int phy_berlin_sata_power_off(struct phy *phy) | ||
132 | { | ||
133 | struct phy_berlin_desc *desc = phy_get_drvdata(phy); | ||
134 | struct phy_berlin_priv *priv = dev_get_drvdata(phy->dev.parent); | ||
135 | u32 regval; | ||
136 | |||
137 | clk_prepare_enable(priv->clk); | ||
138 | |||
139 | spin_lock(&priv->lock); | ||
140 | |||
141 | /* Power down PHY */ | ||
142 | writel(CONTROL_REGISTER, priv->base + HOST_VSA_ADDR); | ||
143 | regval = readl(priv->base + HOST_VSA_DATA); | ||
144 | regval |= desc->power_bit; | ||
145 | writel(regval, priv->base + HOST_VSA_DATA); | ||
146 | |||
147 | spin_unlock(&priv->lock); | ||
148 | |||
149 | clk_disable_unprepare(priv->clk); | ||
150 | |||
151 | return 0; | ||
152 | } | ||
153 | |||
154 | static struct phy *phy_berlin_sata_phy_xlate(struct device *dev, | ||
155 | struct of_phandle_args *args) | ||
156 | { | ||
157 | struct phy_berlin_priv *priv = dev_get_drvdata(dev); | ||
158 | int i; | ||
159 | |||
160 | if (WARN_ON(args->args[0] >= priv->nphys)) | ||
161 | return ERR_PTR(-ENODEV); | ||
162 | |||
163 | for (i = 0; i < priv->nphys; i++) { | ||
164 | if (priv->phys[i]->index == args->args[0]) | ||
165 | break; | ||
166 | } | ||
167 | |||
168 | if (i == priv->nphys) | ||
169 | return ERR_PTR(-ENODEV); | ||
170 | |||
171 | return priv->phys[i]->phy; | ||
172 | } | ||
173 | |||
174 | static struct phy_ops phy_berlin_sata_ops = { | ||
175 | .power_on = phy_berlin_sata_power_on, | ||
176 | .power_off = phy_berlin_sata_power_off, | ||
177 | .owner = THIS_MODULE, | ||
178 | }; | ||
179 | |||
180 | static u32 phy_berlin_power_down_bits[] = { | ||
181 | POWER_DOWN_PHY0, | ||
182 | POWER_DOWN_PHY1, | ||
183 | }; | ||
184 | |||
185 | static int phy_berlin_sata_probe(struct platform_device *pdev) | ||
186 | { | ||
187 | struct device *dev = &pdev->dev; | ||
188 | struct device_node *child; | ||
189 | struct phy *phy; | ||
190 | struct phy_provider *phy_provider; | ||
191 | struct phy_berlin_priv *priv; | ||
192 | struct resource *res; | ||
193 | int i = 0; | ||
194 | u32 phy_id; | ||
195 | |||
196 | priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); | ||
197 | if (!priv) | ||
198 | return -ENOMEM; | ||
199 | |||
200 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
201 | if (!res) | ||
202 | return -EINVAL; | ||
203 | |||
204 | priv->base = devm_ioremap(dev, res->start, resource_size(res)); | ||
205 | if (!priv->base) | ||
206 | return -ENOMEM; | ||
207 | |||
208 | priv->clk = devm_clk_get(dev, NULL); | ||
209 | if (IS_ERR(priv->clk)) | ||
210 | return PTR_ERR(priv->clk); | ||
211 | |||
212 | priv->nphys = of_get_child_count(dev->of_node); | ||
213 | if (priv->nphys == 0) | ||
214 | return -ENODEV; | ||
215 | |||
216 | priv->phys = devm_kzalloc(dev, priv->nphys * sizeof(*priv->phys), | ||
217 | GFP_KERNEL); | ||
218 | if (!priv->phys) | ||
219 | return -ENOMEM; | ||
220 | |||
221 | dev_set_drvdata(dev, priv); | ||
222 | spin_lock_init(&priv->lock); | ||
223 | |||
224 | for_each_available_child_of_node(dev->of_node, child) { | ||
225 | struct phy_berlin_desc *phy_desc; | ||
226 | |||
227 | if (of_property_read_u32(child, "reg", &phy_id)) { | ||
228 | dev_err(dev, "missing reg property in node %s\n", | ||
229 | child->name); | ||
230 | return -EINVAL; | ||
231 | } | ||
232 | |||
233 | if (phy_id >= ARRAY_SIZE(phy_berlin_power_down_bits)) { | ||
234 | dev_err(dev, "invalid reg in node %s\n", child->name); | ||
235 | return -EINVAL; | ||
236 | } | ||
237 | |||
238 | phy_desc = devm_kzalloc(dev, sizeof(*phy_desc), GFP_KERNEL); | ||
239 | if (!phy_desc) | ||
240 | return -ENOMEM; | ||
241 | |||
242 | phy = devm_phy_create(dev, NULL, &phy_berlin_sata_ops, NULL); | ||
243 | if (IS_ERR(phy)) { | ||
244 | dev_err(dev, "failed to create PHY %d\n", phy_id); | ||
245 | return PTR_ERR(phy); | ||
246 | } | ||
247 | |||
248 | phy_desc->phy = phy; | ||
249 | phy_desc->power_bit = phy_berlin_power_down_bits[phy_id]; | ||
250 | phy_desc->index = phy_id; | ||
251 | phy_set_drvdata(phy, phy_desc); | ||
252 | |||
253 | priv->phys[i++] = phy_desc; | ||
254 | |||
255 | /* Make sure the PHY is off */ | ||
256 | phy_berlin_sata_power_off(phy); | ||
257 | } | ||
258 | |||
259 | phy_provider = | ||
260 | devm_of_phy_provider_register(dev, phy_berlin_sata_phy_xlate); | ||
261 | if (IS_ERR(phy_provider)) | ||
262 | return PTR_ERR(phy_provider); | ||
263 | |||
264 | return 0; | ||
265 | } | ||
266 | |||
267 | static const struct of_device_id phy_berlin_sata_of_match[] = { | ||
268 | { .compatible = "marvell,berlin2q-sata-phy" }, | ||
269 | { }, | ||
270 | }; | ||
271 | |||
272 | static struct platform_driver phy_berlin_sata_driver = { | ||
273 | .probe = phy_berlin_sata_probe, | ||
274 | .driver = { | ||
275 | .name = "phy-berlin-sata", | ||
276 | .owner = THIS_MODULE, | ||
277 | .of_match_table = phy_berlin_sata_of_match, | ||
278 | }, | ||
279 | }; | ||
280 | module_platform_driver(phy_berlin_sata_driver); | ||
281 | |||
282 | MODULE_DESCRIPTION("Marvell Berlin SATA PHY driver"); | ||
283 | MODULE_AUTHOR("Antoine Ténart <antoine.tenart@free-electrons.com>"); | ||
284 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c index c64a2f3b2d62..ff5eec5af817 100644 --- a/drivers/phy/phy-core.c +++ b/drivers/phy/phy-core.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <linux/phy/phy.h> | 21 | #include <linux/phy/phy.h> |
22 | #include <linux/idr.h> | 22 | #include <linux/idr.h> |
23 | #include <linux/pm_runtime.h> | 23 | #include <linux/pm_runtime.h> |
24 | #include <linux/regulator/consumer.h> | ||
24 | 25 | ||
25 | static struct class *phy_class; | 26 | static struct class *phy_class; |
26 | static DEFINE_MUTEX(phy_provider_mutex); | 27 | static DEFINE_MUTEX(phy_provider_mutex); |
@@ -86,10 +87,15 @@ static struct phy *phy_lookup(struct device *device, const char *port) | |||
86 | static struct phy_provider *of_phy_provider_lookup(struct device_node *node) | 87 | static struct phy_provider *of_phy_provider_lookup(struct device_node *node) |
87 | { | 88 | { |
88 | struct phy_provider *phy_provider; | 89 | struct phy_provider *phy_provider; |
90 | struct device_node *child; | ||
89 | 91 | ||
90 | list_for_each_entry(phy_provider, &phy_provider_list, list) { | 92 | list_for_each_entry(phy_provider, &phy_provider_list, list) { |
91 | if (phy_provider->dev->of_node == node) | 93 | if (phy_provider->dev->of_node == node) |
92 | return phy_provider; | 94 | return phy_provider; |
95 | |||
96 | for_each_child_of_node(phy_provider->dev->of_node, child) | ||
97 | if (child == node) | ||
98 | return phy_provider; | ||
93 | } | 99 | } |
94 | 100 | ||
95 | return ERR_PTR(-EPROBE_DEFER); | 101 | return ERR_PTR(-EPROBE_DEFER); |
@@ -226,6 +232,12 @@ int phy_power_on(struct phy *phy) | |||
226 | if (!phy) | 232 | if (!phy) |
227 | return 0; | 233 | return 0; |
228 | 234 | ||
235 | if (phy->pwr) { | ||
236 | ret = regulator_enable(phy->pwr); | ||
237 | if (ret) | ||
238 | return ret; | ||
239 | } | ||
240 | |||
229 | ret = phy_pm_runtime_get_sync(phy); | 241 | ret = phy_pm_runtime_get_sync(phy); |
230 | if (ret < 0 && ret != -ENOTSUPP) | 242 | if (ret < 0 && ret != -ENOTSUPP) |
231 | return ret; | 243 | return ret; |
@@ -247,6 +259,8 @@ int phy_power_on(struct phy *phy) | |||
247 | out: | 259 | out: |
248 | mutex_unlock(&phy->mutex); | 260 | mutex_unlock(&phy->mutex); |
249 | phy_pm_runtime_put_sync(phy); | 261 | phy_pm_runtime_put_sync(phy); |
262 | if (phy->pwr) | ||
263 | regulator_disable(phy->pwr); | ||
250 | 264 | ||
251 | return ret; | 265 | return ret; |
252 | } | 266 | } |
@@ -272,6 +286,9 @@ int phy_power_off(struct phy *phy) | |||
272 | mutex_unlock(&phy->mutex); | 286 | mutex_unlock(&phy->mutex); |
273 | phy_pm_runtime_put(phy); | 287 | phy_pm_runtime_put(phy); |
274 | 288 | ||
289 | if (phy->pwr) | ||
290 | regulator_disable(phy->pwr); | ||
291 | |||
275 | return 0; | 292 | return 0; |
276 | } | 293 | } |
277 | EXPORT_SYMBOL_GPL(phy_power_off); | 294 | EXPORT_SYMBOL_GPL(phy_power_off); |
@@ -398,13 +415,20 @@ struct phy *of_phy_simple_xlate(struct device *dev, struct of_phandle_args | |||
398 | struct phy *phy; | 415 | struct phy *phy; |
399 | struct class_dev_iter iter; | 416 | struct class_dev_iter iter; |
400 | struct device_node *node = dev->of_node; | 417 | struct device_node *node = dev->of_node; |
418 | struct device_node *child; | ||
401 | 419 | ||
402 | class_dev_iter_init(&iter, phy_class, NULL, NULL); | 420 | class_dev_iter_init(&iter, phy_class, NULL, NULL); |
403 | while ((dev = class_dev_iter_next(&iter))) { | 421 | while ((dev = class_dev_iter_next(&iter))) { |
404 | phy = to_phy(dev); | 422 | phy = to_phy(dev); |
405 | if (node != phy->dev.of_node) | 423 | if (node != phy->dev.of_node) { |
424 | for_each_child_of_node(node, child) { | ||
425 | if (child == phy->dev.of_node) | ||
426 | goto phy_found; | ||
427 | } | ||
406 | continue; | 428 | continue; |
429 | } | ||
407 | 430 | ||
431 | phy_found: | ||
408 | class_dev_iter_exit(&iter); | 432 | class_dev_iter_exit(&iter); |
409 | return phy; | 433 | return phy; |
410 | } | 434 | } |
@@ -562,13 +586,15 @@ EXPORT_SYMBOL_GPL(devm_of_phy_get); | |||
562 | /** | 586 | /** |
563 | * phy_create() - create a new phy | 587 | * phy_create() - create a new phy |
564 | * @dev: device that is creating the new phy | 588 | * @dev: device that is creating the new phy |
589 | * @node: device node of the phy | ||
565 | * @ops: function pointers for performing phy operations | 590 | * @ops: function pointers for performing phy operations |
566 | * @init_data: contains the list of PHY consumers or NULL | 591 | * @init_data: contains the list of PHY consumers or NULL |
567 | * | 592 | * |
568 | * Called to create a phy using phy framework. | 593 | * Called to create a phy using phy framework. |
569 | */ | 594 | */ |
570 | struct phy *phy_create(struct device *dev, const struct phy_ops *ops, | 595 | struct phy *phy_create(struct device *dev, struct device_node *node, |
571 | struct phy_init_data *init_data) | 596 | const struct phy_ops *ops, |
597 | struct phy_init_data *init_data) | ||
572 | { | 598 | { |
573 | int ret; | 599 | int ret; |
574 | int id; | 600 | int id; |
@@ -588,12 +614,22 @@ struct phy *phy_create(struct device *dev, const struct phy_ops *ops, | |||
588 | goto free_phy; | 614 | goto free_phy; |
589 | } | 615 | } |
590 | 616 | ||
617 | /* phy-supply */ | ||
618 | phy->pwr = regulator_get_optional(dev, "phy"); | ||
619 | if (IS_ERR(phy->pwr)) { | ||
620 | if (PTR_ERR(phy->pwr) == -EPROBE_DEFER) { | ||
621 | ret = -EPROBE_DEFER; | ||
622 | goto free_ida; | ||
623 | } | ||
624 | phy->pwr = NULL; | ||
625 | } | ||
626 | |||
591 | device_initialize(&phy->dev); | 627 | device_initialize(&phy->dev); |
592 | mutex_init(&phy->mutex); | 628 | mutex_init(&phy->mutex); |
593 | 629 | ||
594 | phy->dev.class = phy_class; | 630 | phy->dev.class = phy_class; |
595 | phy->dev.parent = dev; | 631 | phy->dev.parent = dev; |
596 | phy->dev.of_node = dev->of_node; | 632 | phy->dev.of_node = node ?: dev->of_node; |
597 | phy->id = id; | 633 | phy->id = id; |
598 | phy->ops = ops; | 634 | phy->ops = ops; |
599 | phy->init_data = init_data; | 635 | phy->init_data = init_data; |
@@ -614,8 +650,12 @@ struct phy *phy_create(struct device *dev, const struct phy_ops *ops, | |||
614 | return phy; | 650 | return phy; |
615 | 651 | ||
616 | put_dev: | 652 | put_dev: |
617 | put_device(&phy->dev); | 653 | put_device(&phy->dev); /* calls phy_release() which frees resources */ |
618 | ida_remove(&phy_ida, phy->id); | 654 | return ERR_PTR(ret); |
655 | |||
656 | free_ida: | ||
657 | ida_simple_remove(&phy_ida, phy->id); | ||
658 | |||
619 | free_phy: | 659 | free_phy: |
620 | kfree(phy); | 660 | kfree(phy); |
621 | return ERR_PTR(ret); | 661 | return ERR_PTR(ret); |
@@ -625,6 +665,7 @@ EXPORT_SYMBOL_GPL(phy_create); | |||
625 | /** | 665 | /** |
626 | * devm_phy_create() - create a new phy | 666 | * devm_phy_create() - create a new phy |
627 | * @dev: device that is creating the new phy | 667 | * @dev: device that is creating the new phy |
668 | * @node: device node of the phy | ||
628 | * @ops: function pointers for performing phy operations | 669 | * @ops: function pointers for performing phy operations |
629 | * @init_data: contains the list of PHY consumers or NULL | 670 | * @init_data: contains the list of PHY consumers or NULL |
630 | * | 671 | * |
@@ -633,8 +674,9 @@ EXPORT_SYMBOL_GPL(phy_create); | |||
633 | * On driver detach, release function is invoked on the devres data, | 674 | * On driver detach, release function is invoked on the devres data, |
634 | * then, devres data is freed. | 675 | * then, devres data is freed. |
635 | */ | 676 | */ |
636 | struct phy *devm_phy_create(struct device *dev, const struct phy_ops *ops, | 677 | struct phy *devm_phy_create(struct device *dev, struct device_node *node, |
637 | struct phy_init_data *init_data) | 678 | const struct phy_ops *ops, |
679 | struct phy_init_data *init_data) | ||
638 | { | 680 | { |
639 | struct phy **ptr, *phy; | 681 | struct phy **ptr, *phy; |
640 | 682 | ||
@@ -642,7 +684,7 @@ struct phy *devm_phy_create(struct device *dev, const struct phy_ops *ops, | |||
642 | if (!ptr) | 684 | if (!ptr) |
643 | return ERR_PTR(-ENOMEM); | 685 | return ERR_PTR(-ENOMEM); |
644 | 686 | ||
645 | phy = phy_create(dev, ops, init_data); | 687 | phy = phy_create(dev, node, ops, init_data); |
646 | if (!IS_ERR(phy)) { | 688 | if (!IS_ERR(phy)) { |
647 | *ptr = phy; | 689 | *ptr = phy; |
648 | devres_add(dev, ptr); | 690 | devres_add(dev, ptr); |
@@ -799,7 +841,8 @@ static void phy_release(struct device *dev) | |||
799 | 841 | ||
800 | phy = to_phy(dev); | 842 | phy = to_phy(dev); |
801 | dev_vdbg(dev, "releasing '%s'\n", dev_name(dev)); | 843 | dev_vdbg(dev, "releasing '%s'\n", dev_name(dev)); |
802 | ida_remove(&phy_ida, phy->id); | 844 | regulator_put(phy->pwr); |
845 | ida_simple_remove(&phy_ida, phy->id); | ||
803 | kfree(phy); | 846 | kfree(phy); |
804 | } | 847 | } |
805 | 848 | ||
diff --git a/drivers/phy/phy-exynos-dp-video.c b/drivers/phy/phy-exynos-dp-video.c index 0786fef842e7..8b3026e2af7f 100644 --- a/drivers/phy/phy-exynos-dp-video.c +++ b/drivers/phy/phy-exynos-dp-video.c | |||
@@ -9,6 +9,7 @@ | |||
9 | * published by the Free Software Foundation. | 9 | * published by the Free Software Foundation. |
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include <linux/err.h> | ||
12 | #include <linux/io.h> | 13 | #include <linux/io.h> |
13 | #include <linux/kernel.h> | 14 | #include <linux/kernel.h> |
14 | #include <linux/module.h> | 15 | #include <linux/module.h> |
@@ -76,7 +77,7 @@ static int exynos_dp_video_phy_probe(struct platform_device *pdev) | |||
76 | if (IS_ERR(state->regs)) | 77 | if (IS_ERR(state->regs)) |
77 | return PTR_ERR(state->regs); | 78 | return PTR_ERR(state->regs); |
78 | 79 | ||
79 | phy = devm_phy_create(dev, &exynos_dp_video_phy_ops, NULL); | 80 | phy = devm_phy_create(dev, NULL, &exynos_dp_video_phy_ops, NULL); |
80 | if (IS_ERR(phy)) { | 81 | if (IS_ERR(phy)) { |
81 | dev_err(dev, "failed to create Display Port PHY\n"); | 82 | dev_err(dev, "failed to create Display Port PHY\n"); |
82 | return PTR_ERR(phy); | 83 | return PTR_ERR(phy); |
@@ -84,10 +85,8 @@ static int exynos_dp_video_phy_probe(struct platform_device *pdev) | |||
84 | phy_set_drvdata(phy, state); | 85 | phy_set_drvdata(phy, state); |
85 | 86 | ||
86 | phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); | 87 | phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); |
87 | if (IS_ERR(phy_provider)) | ||
88 | return PTR_ERR(phy_provider); | ||
89 | 88 | ||
90 | return 0; | 89 | return PTR_ERR_OR_ZERO(phy_provider); |
91 | } | 90 | } |
92 | 91 | ||
93 | static const struct of_device_id exynos_dp_video_phy_of_match[] = { | 92 | static const struct of_device_id exynos_dp_video_phy_of_match[] = { |
diff --git a/drivers/phy/phy-exynos-mipi-video.c b/drivers/phy/phy-exynos-mipi-video.c index ff026689358c..b55a92e12496 100644 --- a/drivers/phy/phy-exynos-mipi-video.c +++ b/drivers/phy/phy-exynos-mipi-video.c | |||
@@ -9,6 +9,7 @@ | |||
9 | * published by the Free Software Foundation. | 9 | * published by the Free Software Foundation. |
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include <linux/err.h> | ||
12 | #include <linux/io.h> | 13 | #include <linux/io.h> |
13 | #include <linux/kernel.h> | 14 | #include <linux/kernel.h> |
14 | #include <linux/module.h> | 15 | #include <linux/module.h> |
@@ -135,7 +136,7 @@ static int exynos_mipi_video_phy_probe(struct platform_device *pdev) | |||
135 | spin_lock_init(&state->slock); | 136 | spin_lock_init(&state->slock); |
136 | 137 | ||
137 | for (i = 0; i < EXYNOS_MIPI_PHYS_NUM; i++) { | 138 | for (i = 0; i < EXYNOS_MIPI_PHYS_NUM; i++) { |
138 | struct phy *phy = devm_phy_create(dev, | 139 | struct phy *phy = devm_phy_create(dev, NULL, |
139 | &exynos_mipi_video_phy_ops, NULL); | 140 | &exynos_mipi_video_phy_ops, NULL); |
140 | if (IS_ERR(phy)) { | 141 | if (IS_ERR(phy)) { |
141 | dev_err(dev, "failed to create PHY %d\n", i); | 142 | dev_err(dev, "failed to create PHY %d\n", i); |
@@ -149,10 +150,8 @@ static int exynos_mipi_video_phy_probe(struct platform_device *pdev) | |||
149 | 150 | ||
150 | phy_provider = devm_of_phy_provider_register(dev, | 151 | phy_provider = devm_of_phy_provider_register(dev, |
151 | exynos_mipi_video_phy_xlate); | 152 | exynos_mipi_video_phy_xlate); |
152 | if (IS_ERR(phy_provider)) | ||
153 | return PTR_ERR(phy_provider); | ||
154 | 153 | ||
155 | return 0; | 154 | return PTR_ERR_OR_ZERO(phy_provider); |
156 | } | 155 | } |
157 | 156 | ||
158 | static const struct of_device_id exynos_mipi_video_phy_of_match[] = { | 157 | static const struct of_device_id exynos_mipi_video_phy_of_match[] = { |
diff --git a/drivers/phy/phy-exynos4x12-usb2.c b/drivers/phy/phy-exynos4x12-usb2.c index d92a7cc5698a..0b9de88579b1 100644 --- a/drivers/phy/phy-exynos4x12-usb2.c +++ b/drivers/phy/phy-exynos4x12-usb2.c | |||
@@ -67,6 +67,8 @@ | |||
67 | #define EXYNOS_4x12_UPHYCLK_PHYFSEL_24MHZ (0x5 << 0) | 67 | #define EXYNOS_4x12_UPHYCLK_PHYFSEL_24MHZ (0x5 << 0) |
68 | #define EXYNOS_4x12_UPHYCLK_PHYFSEL_50MHZ (0x7 << 0) | 68 | #define EXYNOS_4x12_UPHYCLK_PHYFSEL_50MHZ (0x7 << 0) |
69 | 69 | ||
70 | #define EXYNOS_3250_UPHYCLK_REFCLKSEL (0x2 << 8) | ||
71 | |||
70 | #define EXYNOS_4x12_UPHYCLK_PHY0_ID_PULLUP BIT(3) | 72 | #define EXYNOS_4x12_UPHYCLK_PHY0_ID_PULLUP BIT(3) |
71 | #define EXYNOS_4x12_UPHYCLK_PHY0_COMMON_ON BIT(4) | 73 | #define EXYNOS_4x12_UPHYCLK_PHY0_COMMON_ON BIT(4) |
72 | #define EXYNOS_4x12_UPHYCLK_PHY1_COMMON_ON BIT(7) | 74 | #define EXYNOS_4x12_UPHYCLK_PHY1_COMMON_ON BIT(7) |
@@ -86,13 +88,23 @@ | |||
86 | #define EXYNOS_4x12_URSTCON_OTG_HLINK BIT(1) | 88 | #define EXYNOS_4x12_URSTCON_OTG_HLINK BIT(1) |
87 | #define EXYNOS_4x12_URSTCON_OTG_PHYLINK BIT(2) | 89 | #define EXYNOS_4x12_URSTCON_OTG_PHYLINK BIT(2) |
88 | #define EXYNOS_4x12_URSTCON_HOST_PHY BIT(3) | 90 | #define EXYNOS_4x12_URSTCON_HOST_PHY BIT(3) |
91 | /* The following bit defines are presented in the | ||
92 | * order taken from the Exynos4412 reference manual. | ||
93 | * | ||
94 | * During experiments with the hardware and debugging | ||
95 | * it was determined that the hardware behaves contrary | ||
96 | * to the manual. | ||
97 | * | ||
98 | * The following bit values were chaned accordingly to the | ||
99 | * results of real hardware experiments. | ||
100 | */ | ||
89 | #define EXYNOS_4x12_URSTCON_PHY1 BIT(4) | 101 | #define EXYNOS_4x12_URSTCON_PHY1 BIT(4) |
90 | #define EXYNOS_4x12_URSTCON_HSIC0 BIT(5) | 102 | #define EXYNOS_4x12_URSTCON_HSIC0 BIT(6) |
91 | #define EXYNOS_4x12_URSTCON_HSIC1 BIT(6) | 103 | #define EXYNOS_4x12_URSTCON_HSIC1 BIT(5) |
92 | #define EXYNOS_4x12_URSTCON_HOST_LINK_ALL BIT(7) | 104 | #define EXYNOS_4x12_URSTCON_HOST_LINK_ALL BIT(7) |
93 | #define EXYNOS_4x12_URSTCON_HOST_LINK_P0 BIT(8) | 105 | #define EXYNOS_4x12_URSTCON_HOST_LINK_P0 BIT(10) |
94 | #define EXYNOS_4x12_URSTCON_HOST_LINK_P1 BIT(9) | 106 | #define EXYNOS_4x12_URSTCON_HOST_LINK_P1 BIT(9) |
95 | #define EXYNOS_4x12_URSTCON_HOST_LINK_P2 BIT(10) | 107 | #define EXYNOS_4x12_URSTCON_HOST_LINK_P2 BIT(8) |
96 | 108 | ||
97 | /* Isolation, configured in the power management unit */ | 109 | /* Isolation, configured in the power management unit */ |
98 | #define EXYNOS_4x12_USB_ISOL_OFFSET 0x704 | 110 | #define EXYNOS_4x12_USB_ISOL_OFFSET 0x704 |
@@ -187,7 +199,12 @@ static void exynos4x12_setup_clk(struct samsung_usb2_phy_instance *inst) | |||
187 | 199 | ||
188 | clk = readl(drv->reg_phy + EXYNOS_4x12_UPHYCLK); | 200 | clk = readl(drv->reg_phy + EXYNOS_4x12_UPHYCLK); |
189 | clk &= ~EXYNOS_4x12_UPHYCLK_PHYFSEL_MASK; | 201 | clk &= ~EXYNOS_4x12_UPHYCLK_PHYFSEL_MASK; |
202 | |||
203 | if (drv->cfg->has_refclk_sel) | ||
204 | clk = EXYNOS_3250_UPHYCLK_REFCLKSEL; | ||
205 | |||
190 | clk |= drv->ref_reg_val << EXYNOS_4x12_UPHYCLK_PHYFSEL_OFFSET; | 206 | clk |= drv->ref_reg_val << EXYNOS_4x12_UPHYCLK_PHYFSEL_OFFSET; |
207 | clk |= EXYNOS_4x12_UPHYCLK_PHY1_COMMON_ON; | ||
191 | writel(clk, drv->reg_phy + EXYNOS_4x12_UPHYCLK); | 208 | writel(clk, drv->reg_phy + EXYNOS_4x12_UPHYCLK); |
192 | } | 209 | } |
193 | 210 | ||
@@ -198,27 +215,22 @@ static void exynos4x12_phy_pwr(struct samsung_usb2_phy_instance *inst, bool on) | |||
198 | u32 phypwr = 0; | 215 | u32 phypwr = 0; |
199 | u32 rst; | 216 | u32 rst; |
200 | u32 pwr; | 217 | u32 pwr; |
201 | u32 mode = 0; | ||
202 | u32 switch_mode = 0; | ||
203 | 218 | ||
204 | switch (inst->cfg->id) { | 219 | switch (inst->cfg->id) { |
205 | case EXYNOS4x12_DEVICE: | 220 | case EXYNOS4x12_DEVICE: |
206 | phypwr = EXYNOS_4x12_UPHYPWR_PHY0; | 221 | phypwr = EXYNOS_4x12_UPHYPWR_PHY0; |
207 | rstbits = EXYNOS_4x12_URSTCON_PHY0; | 222 | rstbits = EXYNOS_4x12_URSTCON_PHY0; |
208 | mode = EXYNOS_4x12_MODE_SWITCH_DEVICE; | ||
209 | switch_mode = 1; | ||
210 | break; | 223 | break; |
211 | case EXYNOS4x12_HOST: | 224 | case EXYNOS4x12_HOST: |
212 | phypwr = EXYNOS_4x12_UPHYPWR_PHY1; | 225 | phypwr = EXYNOS_4x12_UPHYPWR_PHY1; |
213 | rstbits = EXYNOS_4x12_URSTCON_HOST_PHY; | 226 | rstbits = EXYNOS_4x12_URSTCON_HOST_PHY | |
214 | mode = EXYNOS_4x12_MODE_SWITCH_HOST; | 227 | EXYNOS_4x12_URSTCON_PHY1 | |
215 | switch_mode = 1; | 228 | EXYNOS_4x12_URSTCON_HOST_LINK_P0; |
216 | break; | 229 | break; |
217 | case EXYNOS4x12_HSIC0: | 230 | case EXYNOS4x12_HSIC0: |
218 | phypwr = EXYNOS_4x12_UPHYPWR_HSIC0; | 231 | phypwr = EXYNOS_4x12_UPHYPWR_HSIC0; |
219 | rstbits = EXYNOS_4x12_URSTCON_HSIC1 | | 232 | rstbits = EXYNOS_4x12_URSTCON_HSIC0 | |
220 | EXYNOS_4x12_URSTCON_HOST_LINK_P0 | | 233 | EXYNOS_4x12_URSTCON_HOST_LINK_P1; |
221 | EXYNOS_4x12_URSTCON_HOST_PHY; | ||
222 | break; | 234 | break; |
223 | case EXYNOS4x12_HSIC1: | 235 | case EXYNOS4x12_HSIC1: |
224 | phypwr = EXYNOS_4x12_UPHYPWR_HSIC1; | 236 | phypwr = EXYNOS_4x12_UPHYPWR_HSIC1; |
@@ -228,11 +240,6 @@ static void exynos4x12_phy_pwr(struct samsung_usb2_phy_instance *inst, bool on) | |||
228 | }; | 240 | }; |
229 | 241 | ||
230 | if (on) { | 242 | if (on) { |
231 | if (switch_mode) | ||
232 | regmap_update_bits(drv->reg_sys, | ||
233 | EXYNOS_4x12_MODE_SWITCH_OFFSET, | ||
234 | EXYNOS_4x12_MODE_SWITCH_MASK, mode); | ||
235 | |||
236 | pwr = readl(drv->reg_phy + EXYNOS_4x12_UPHYPWR); | 243 | pwr = readl(drv->reg_phy + EXYNOS_4x12_UPHYPWR); |
237 | pwr &= ~phypwr; | 244 | pwr &= ~phypwr; |
238 | writel(pwr, drv->reg_phy + EXYNOS_4x12_UPHYPWR); | 245 | writel(pwr, drv->reg_phy + EXYNOS_4x12_UPHYPWR); |
@@ -253,41 +260,78 @@ static void exynos4x12_phy_pwr(struct samsung_usb2_phy_instance *inst, bool on) | |||
253 | } | 260 | } |
254 | } | 261 | } |
255 | 262 | ||
256 | static int exynos4x12_power_on(struct samsung_usb2_phy_instance *inst) | 263 | static void exynos4x12_power_on_int(struct samsung_usb2_phy_instance *inst) |
257 | { | 264 | { |
258 | struct samsung_usb2_phy_driver *drv = inst->drv; | 265 | if (inst->int_cnt++ > 0) |
266 | return; | ||
259 | 267 | ||
260 | inst->enabled = 1; | ||
261 | exynos4x12_setup_clk(inst); | 268 | exynos4x12_setup_clk(inst); |
262 | exynos4x12_phy_pwr(inst, 1); | ||
263 | exynos4x12_isol(inst, 0); | 269 | exynos4x12_isol(inst, 0); |
270 | exynos4x12_phy_pwr(inst, 1); | ||
271 | } | ||
272 | |||
273 | static int exynos4x12_power_on(struct samsung_usb2_phy_instance *inst) | ||
274 | { | ||
275 | struct samsung_usb2_phy_driver *drv = inst->drv; | ||
276 | |||
277 | if (inst->ext_cnt++ > 0) | ||
278 | return 0; | ||
264 | 279 | ||
265 | /* Power on the device, as it is necessary for HSIC to work */ | 280 | if (inst->cfg->id == EXYNOS4x12_HOST) { |
266 | if (inst->cfg->id == EXYNOS4x12_HSIC0) { | 281 | regmap_update_bits(drv->reg_sys, EXYNOS_4x12_MODE_SWITCH_OFFSET, |
267 | struct samsung_usb2_phy_instance *device = | 282 | EXYNOS_4x12_MODE_SWITCH_MASK, |
268 | &drv->instances[EXYNOS4x12_DEVICE]; | 283 | EXYNOS_4x12_MODE_SWITCH_HOST); |
269 | exynos4x12_phy_pwr(device, 1); | 284 | exynos4x12_power_on_int(&drv->instances[EXYNOS4x12_DEVICE]); |
270 | exynos4x12_isol(device, 0); | ||
271 | } | 285 | } |
272 | 286 | ||
287 | if (inst->cfg->id == EXYNOS4x12_DEVICE && drv->cfg->has_mode_switch) | ||
288 | regmap_update_bits(drv->reg_sys, EXYNOS_4x12_MODE_SWITCH_OFFSET, | ||
289 | EXYNOS_4x12_MODE_SWITCH_MASK, | ||
290 | EXYNOS_4x12_MODE_SWITCH_DEVICE); | ||
291 | |||
292 | if (inst->cfg->id == EXYNOS4x12_HSIC0 || | ||
293 | inst->cfg->id == EXYNOS4x12_HSIC1) { | ||
294 | exynos4x12_power_on_int(&drv->instances[EXYNOS4x12_DEVICE]); | ||
295 | exynos4x12_power_on_int(&drv->instances[EXYNOS4x12_HOST]); | ||
296 | } | ||
297 | |||
298 | exynos4x12_power_on_int(inst); | ||
299 | |||
273 | return 0; | 300 | return 0; |
274 | } | 301 | } |
275 | 302 | ||
276 | static int exynos4x12_power_off(struct samsung_usb2_phy_instance *inst) | 303 | static void exynos4x12_power_off_int(struct samsung_usb2_phy_instance *inst) |
277 | { | 304 | { |
278 | struct samsung_usb2_phy_driver *drv = inst->drv; | 305 | if (inst->int_cnt-- > 1) |
279 | struct samsung_usb2_phy_instance *device = | 306 | return; |
280 | &drv->instances[EXYNOS4x12_DEVICE]; | ||
281 | 307 | ||
282 | inst->enabled = 0; | ||
283 | exynos4x12_isol(inst, 1); | 308 | exynos4x12_isol(inst, 1); |
284 | exynos4x12_phy_pwr(inst, 0); | 309 | exynos4x12_phy_pwr(inst, 0); |
310 | } | ||
311 | |||
312 | static int exynos4x12_power_off(struct samsung_usb2_phy_instance *inst) | ||
313 | { | ||
314 | struct samsung_usb2_phy_driver *drv = inst->drv; | ||
315 | |||
316 | if (inst->ext_cnt-- > 1) | ||
317 | return 0; | ||
318 | |||
319 | if (inst->cfg->id == EXYNOS4x12_DEVICE && drv->cfg->has_mode_switch) | ||
320 | regmap_update_bits(drv->reg_sys, EXYNOS_4x12_MODE_SWITCH_OFFSET, | ||
321 | EXYNOS_4x12_MODE_SWITCH_MASK, | ||
322 | EXYNOS_4x12_MODE_SWITCH_HOST); | ||
323 | |||
324 | if (inst->cfg->id == EXYNOS4x12_HOST) | ||
325 | exynos4x12_power_off_int(&drv->instances[EXYNOS4x12_DEVICE]); | ||
285 | 326 | ||
286 | if (inst->cfg->id == EXYNOS4x12_HSIC0 && !device->enabled) { | 327 | if (inst->cfg->id == EXYNOS4x12_HSIC0 || |
287 | exynos4x12_isol(device, 1); | 328 | inst->cfg->id == EXYNOS4x12_HSIC1) { |
288 | exynos4x12_phy_pwr(device, 0); | 329 | exynos4x12_power_off_int(&drv->instances[EXYNOS4x12_DEVICE]); |
330 | exynos4x12_power_off_int(&drv->instances[EXYNOS4x12_HOST]); | ||
289 | } | 331 | } |
290 | 332 | ||
333 | exynos4x12_power_off_int(inst); | ||
334 | |||
291 | return 0; | 335 | return 0; |
292 | } | 336 | } |
293 | 337 | ||
@@ -320,6 +364,13 @@ static const struct samsung_usb2_common_phy exynos4x12_phys[] = { | |||
320 | {}, | 364 | {}, |
321 | }; | 365 | }; |
322 | 366 | ||
367 | const struct samsung_usb2_phy_config exynos3250_usb2_phy_config = { | ||
368 | .has_refclk_sel = 1, | ||
369 | .num_phys = 1, | ||
370 | .phys = exynos4x12_phys, | ||
371 | .rate_to_clk = exynos4x12_rate_to_clk, | ||
372 | }; | ||
373 | |||
323 | const struct samsung_usb2_phy_config exynos4x12_usb2_phy_config = { | 374 | const struct samsung_usb2_phy_config exynos4x12_usb2_phy_config = { |
324 | .has_mode_switch = 1, | 375 | .has_mode_switch = 1, |
325 | .num_phys = EXYNOS4x12_NUM_PHYS, | 376 | .num_phys = EXYNOS4x12_NUM_PHYS, |
diff --git a/drivers/phy/phy-exynos5-usbdrd.c b/drivers/phy/phy-exynos5-usbdrd.c index 76d862b2202f..b05302b09c9f 100644 --- a/drivers/phy/phy-exynos5-usbdrd.c +++ b/drivers/phy/phy-exynos5-usbdrd.c | |||
@@ -506,7 +506,7 @@ static struct phy_ops exynos5_usbdrd_phy_ops = { | |||
506 | .owner = THIS_MODULE, | 506 | .owner = THIS_MODULE, |
507 | }; | 507 | }; |
508 | 508 | ||
509 | const struct exynos5_usbdrd_phy_config phy_cfg_exynos5[] = { | 509 | static const struct exynos5_usbdrd_phy_config phy_cfg_exynos5[] = { |
510 | { | 510 | { |
511 | .id = EXYNOS5_DRDPHY_UTMI, | 511 | .id = EXYNOS5_DRDPHY_UTMI, |
512 | .phy_isol = exynos5_usbdrd_phy_isol, | 512 | .phy_isol = exynos5_usbdrd_phy_isol, |
@@ -521,13 +521,13 @@ const struct exynos5_usbdrd_phy_config phy_cfg_exynos5[] = { | |||
521 | }, | 521 | }, |
522 | }; | 522 | }; |
523 | 523 | ||
524 | const struct exynos5_usbdrd_phy_drvdata exynos5420_usbdrd_phy = { | 524 | static const struct exynos5_usbdrd_phy_drvdata exynos5420_usbdrd_phy = { |
525 | .phy_cfg = phy_cfg_exynos5, | 525 | .phy_cfg = phy_cfg_exynos5, |
526 | .pmu_offset_usbdrd0_phy = EXYNOS5_USBDRD_PHY_CONTROL, | 526 | .pmu_offset_usbdrd0_phy = EXYNOS5_USBDRD_PHY_CONTROL, |
527 | .pmu_offset_usbdrd1_phy = EXYNOS5420_USBDRD1_PHY_CONTROL, | 527 | .pmu_offset_usbdrd1_phy = EXYNOS5420_USBDRD1_PHY_CONTROL, |
528 | }; | 528 | }; |
529 | 529 | ||
530 | const struct exynos5_usbdrd_phy_drvdata exynos5250_usbdrd_phy = { | 530 | static const struct exynos5_usbdrd_phy_drvdata exynos5250_usbdrd_phy = { |
531 | .phy_cfg = phy_cfg_exynos5, | 531 | .phy_cfg = phy_cfg_exynos5, |
532 | .pmu_offset_usbdrd0_phy = EXYNOS5_USBDRD_PHY_CONTROL, | 532 | .pmu_offset_usbdrd0_phy = EXYNOS5_USBDRD_PHY_CONTROL, |
533 | }; | 533 | }; |
@@ -635,7 +635,8 @@ static int exynos5_usbdrd_phy_probe(struct platform_device *pdev) | |||
635 | dev_vdbg(dev, "Creating usbdrd_phy phy\n"); | 635 | dev_vdbg(dev, "Creating usbdrd_phy phy\n"); |
636 | 636 | ||
637 | for (i = 0; i < EXYNOS5_DRDPHYS_NUM; i++) { | 637 | for (i = 0; i < EXYNOS5_DRDPHYS_NUM; i++) { |
638 | struct phy *phy = devm_phy_create(dev, &exynos5_usbdrd_phy_ops, | 638 | struct phy *phy = devm_phy_create(dev, NULL, |
639 | &exynos5_usbdrd_phy_ops, | ||
639 | NULL); | 640 | NULL); |
640 | if (IS_ERR(phy)) { | 641 | if (IS_ERR(phy)) { |
641 | dev_err(dev, "Failed to create usbdrd_phy phy\n"); | 642 | dev_err(dev, "Failed to create usbdrd_phy phy\n"); |
diff --git a/drivers/phy/phy-exynos5250-sata.c b/drivers/phy/phy-exynos5250-sata.c index 05689450f93b..19a679aca4ac 100644 --- a/drivers/phy/phy-exynos5250-sata.c +++ b/drivers/phy/phy-exynos5250-sata.c | |||
@@ -210,7 +210,7 @@ static int exynos_sata_phy_probe(struct platform_device *pdev) | |||
210 | return ret; | 210 | return ret; |
211 | } | 211 | } |
212 | 212 | ||
213 | sata_phy->phy = devm_phy_create(dev, &exynos_sata_phy_ops, NULL); | 213 | sata_phy->phy = devm_phy_create(dev, NULL, &exynos_sata_phy_ops, NULL); |
214 | if (IS_ERR(sata_phy->phy)) { | 214 | if (IS_ERR(sata_phy->phy)) { |
215 | clk_disable_unprepare(sata_phy->phyclk); | 215 | clk_disable_unprepare(sata_phy->phyclk); |
216 | dev_err(dev, "failed to create PHY\n"); | 216 | dev_err(dev, "failed to create PHY\n"); |
diff --git a/drivers/phy/phy-exynos5250-usb2.c b/drivers/phy/phy-exynos5250-usb2.c index 94179afda951..1c139aa0d074 100644 --- a/drivers/phy/phy-exynos5250-usb2.c +++ b/drivers/phy/phy-exynos5250-usb2.c | |||
@@ -318,7 +318,6 @@ static int exynos5250_power_on(struct samsung_usb2_phy_instance *inst) | |||
318 | 318 | ||
319 | break; | 319 | break; |
320 | } | 320 | } |
321 | inst->enabled = 1; | ||
322 | exynos5250_isol(inst, 0); | 321 | exynos5250_isol(inst, 0); |
323 | 322 | ||
324 | return 0; | 323 | return 0; |
@@ -331,7 +330,6 @@ static int exynos5250_power_off(struct samsung_usb2_phy_instance *inst) | |||
331 | u32 otg; | 330 | u32 otg; |
332 | u32 hsic; | 331 | u32 hsic; |
333 | 332 | ||
334 | inst->enabled = 0; | ||
335 | exynos5250_isol(inst, 1); | 333 | exynos5250_isol(inst, 1); |
336 | 334 | ||
337 | switch (inst->cfg->id) { | 335 | switch (inst->cfg->id) { |
diff --git a/drivers/phy/phy-hix5hd2-sata.c b/drivers/phy/phy-hix5hd2-sata.c new file mode 100644 index 000000000000..6a08fa5f81eb --- /dev/null +++ b/drivers/phy/phy-hix5hd2-sata.c | |||
@@ -0,0 +1,192 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2014 Linaro Ltd. | ||
3 | * Copyright (c) 2014 Hisilicon Limited. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | */ | ||
10 | |||
11 | #include <linux/delay.h> | ||
12 | #include <linux/io.h> | ||
13 | #include <linux/mfd/syscon.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/phy/phy.h> | ||
16 | #include <linux/platform_device.h> | ||
17 | #include <linux/regmap.h> | ||
18 | |||
19 | #define SATA_PHY0_CTLL 0xa0 | ||
20 | #define MPLL_MULTIPLIER_SHIFT 1 | ||
21 | #define MPLL_MULTIPLIER_MASK 0xfe | ||
22 | #define MPLL_MULTIPLIER_50M 0x3c | ||
23 | #define MPLL_MULTIPLIER_100M 0x1e | ||
24 | #define PHY_RESET BIT(0) | ||
25 | #define REF_SSP_EN BIT(9) | ||
26 | #define SSC_EN BIT(10) | ||
27 | #define REF_USE_PAD BIT(23) | ||
28 | |||
29 | #define SATA_PORT_PHYCTL 0x174 | ||
30 | #define SPEED_MODE_MASK 0x6f0000 | ||
31 | #define HALF_RATE_SHIFT 16 | ||
32 | #define PHY_CONFIG_SHIFT 18 | ||
33 | #define GEN2_EN_SHIFT 21 | ||
34 | #define SPEED_CTRL BIT(20) | ||
35 | |||
36 | #define SATA_PORT_PHYCTL1 0x148 | ||
37 | #define AMPLITUDE_MASK 0x3ffffe | ||
38 | #define AMPLITUDE_GEN3 0x68 | ||
39 | #define AMPLITUDE_GEN3_SHIFT 15 | ||
40 | #define AMPLITUDE_GEN2 0x56 | ||
41 | #define AMPLITUDE_GEN2_SHIFT 8 | ||
42 | #define AMPLITUDE_GEN1 0x56 | ||
43 | #define AMPLITUDE_GEN1_SHIFT 1 | ||
44 | |||
45 | #define SATA_PORT_PHYCTL2 0x14c | ||
46 | #define PREEMPH_MASK 0x3ffff | ||
47 | #define PREEMPH_GEN3 0x20 | ||
48 | #define PREEMPH_GEN3_SHIFT 12 | ||
49 | #define PREEMPH_GEN2 0x15 | ||
50 | #define PREEMPH_GEN2_SHIFT 6 | ||
51 | #define PREEMPH_GEN1 0x5 | ||
52 | #define PREEMPH_GEN1_SHIFT 0 | ||
53 | |||
54 | struct hix5hd2_priv { | ||
55 | void __iomem *base; | ||
56 | struct regmap *peri_ctrl; | ||
57 | }; | ||
58 | |||
59 | enum phy_speed_mode { | ||
60 | SPEED_MODE_GEN1 = 0, | ||
61 | SPEED_MODE_GEN2 = 1, | ||
62 | SPEED_MODE_GEN3 = 2, | ||
63 | }; | ||
64 | |||
65 | static int hix5hd2_sata_phy_init(struct phy *phy) | ||
66 | { | ||
67 | struct hix5hd2_priv *priv = phy_get_drvdata(phy); | ||
68 | u32 val, data[2]; | ||
69 | int ret; | ||
70 | |||
71 | if (priv->peri_ctrl) { | ||
72 | ret = of_property_read_u32_array(phy->dev.of_node, | ||
73 | "hisilicon,power-reg", | ||
74 | &data[0], 2); | ||
75 | if (ret) { | ||
76 | dev_err(&phy->dev, "Fail read hisilicon,power-reg\n"); | ||
77 | return ret; | ||
78 | } | ||
79 | |||
80 | regmap_update_bits(priv->peri_ctrl, data[0], | ||
81 | BIT(data[1]), BIT(data[1])); | ||
82 | } | ||
83 | |||
84 | /* reset phy */ | ||
85 | val = readl_relaxed(priv->base + SATA_PHY0_CTLL); | ||
86 | val &= ~(MPLL_MULTIPLIER_MASK | REF_USE_PAD); | ||
87 | val |= MPLL_MULTIPLIER_50M << MPLL_MULTIPLIER_SHIFT | | ||
88 | REF_SSP_EN | PHY_RESET; | ||
89 | writel_relaxed(val, priv->base + SATA_PHY0_CTLL); | ||
90 | msleep(20); | ||
91 | val &= ~PHY_RESET; | ||
92 | writel_relaxed(val, priv->base + SATA_PHY0_CTLL); | ||
93 | |||
94 | val = readl_relaxed(priv->base + SATA_PORT_PHYCTL1); | ||
95 | val &= ~AMPLITUDE_MASK; | ||
96 | val |= AMPLITUDE_GEN3 << AMPLITUDE_GEN3_SHIFT | | ||
97 | AMPLITUDE_GEN2 << AMPLITUDE_GEN2_SHIFT | | ||
98 | AMPLITUDE_GEN1 << AMPLITUDE_GEN1_SHIFT; | ||
99 | writel_relaxed(val, priv->base + SATA_PORT_PHYCTL1); | ||
100 | |||
101 | val = readl_relaxed(priv->base + SATA_PORT_PHYCTL2); | ||
102 | val &= ~PREEMPH_MASK; | ||
103 | val |= PREEMPH_GEN3 << PREEMPH_GEN3_SHIFT | | ||
104 | PREEMPH_GEN2 << PREEMPH_GEN2_SHIFT | | ||
105 | PREEMPH_GEN1 << PREEMPH_GEN1_SHIFT; | ||
106 | writel_relaxed(val, priv->base + SATA_PORT_PHYCTL2); | ||
107 | |||
108 | /* ensure PHYCTRL setting takes effect */ | ||
109 | val = readl_relaxed(priv->base + SATA_PORT_PHYCTL); | ||
110 | val &= ~SPEED_MODE_MASK; | ||
111 | val |= SPEED_MODE_GEN1 << HALF_RATE_SHIFT | | ||
112 | SPEED_MODE_GEN1 << PHY_CONFIG_SHIFT | | ||
113 | SPEED_MODE_GEN1 << GEN2_EN_SHIFT | SPEED_CTRL; | ||
114 | writel_relaxed(val, priv->base + SATA_PORT_PHYCTL); | ||
115 | |||
116 | msleep(20); | ||
117 | val &= ~SPEED_MODE_MASK; | ||
118 | val |= SPEED_MODE_GEN3 << HALF_RATE_SHIFT | | ||
119 | SPEED_MODE_GEN3 << PHY_CONFIG_SHIFT | | ||
120 | SPEED_MODE_GEN3 << GEN2_EN_SHIFT | SPEED_CTRL; | ||
121 | writel_relaxed(val, priv->base + SATA_PORT_PHYCTL); | ||
122 | |||
123 | val &= ~(SPEED_MODE_MASK | SPEED_CTRL); | ||
124 | val |= SPEED_MODE_GEN2 << HALF_RATE_SHIFT | | ||
125 | SPEED_MODE_GEN2 << PHY_CONFIG_SHIFT | | ||
126 | SPEED_MODE_GEN2 << GEN2_EN_SHIFT; | ||
127 | writel_relaxed(val, priv->base + SATA_PORT_PHYCTL); | ||
128 | |||
129 | return 0; | ||
130 | } | ||
131 | |||
132 | static struct phy_ops hix5hd2_sata_phy_ops = { | ||
133 | .init = hix5hd2_sata_phy_init, | ||
134 | .owner = THIS_MODULE, | ||
135 | }; | ||
136 | |||
137 | static int hix5hd2_sata_phy_probe(struct platform_device *pdev) | ||
138 | { | ||
139 | struct phy_provider *phy_provider; | ||
140 | struct device *dev = &pdev->dev; | ||
141 | struct resource *res; | ||
142 | struct phy *phy; | ||
143 | struct hix5hd2_priv *priv; | ||
144 | |||
145 | priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); | ||
146 | if (!priv) | ||
147 | return -ENOMEM; | ||
148 | |||
149 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
150 | priv->base = devm_ioremap(dev, res->start, resource_size(res)); | ||
151 | if (!priv->base) | ||
152 | return -ENOMEM; | ||
153 | |||
154 | priv->peri_ctrl = syscon_regmap_lookup_by_phandle(dev->of_node, | ||
155 | "hisilicon,peripheral-syscon"); | ||
156 | if (IS_ERR(priv->peri_ctrl)) | ||
157 | priv->peri_ctrl = NULL; | ||
158 | |||
159 | phy = devm_phy_create(dev, NULL, &hix5hd2_sata_phy_ops, NULL); | ||
160 | if (IS_ERR(phy)) { | ||
161 | dev_err(dev, "failed to create PHY\n"); | ||
162 | return PTR_ERR(phy); | ||
163 | } | ||
164 | |||
165 | phy_set_drvdata(phy, priv); | ||
166 | phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); | ||
167 | if (IS_ERR(phy_provider)) | ||
168 | return PTR_ERR(phy_provider); | ||
169 | |||
170 | return 0; | ||
171 | } | ||
172 | |||
173 | static const struct of_device_id hix5hd2_sata_phy_of_match[] = { | ||
174 | {.compatible = "hisilicon,hix5hd2-sata-phy",}, | ||
175 | { }, | ||
176 | }; | ||
177 | MODULE_DEVICE_TABLE(of, hix5hd2_sata_phy_of_match); | ||
178 | |||
179 | static struct platform_driver hix5hd2_sata_phy_driver = { | ||
180 | .probe = hix5hd2_sata_phy_probe, | ||
181 | .driver = { | ||
182 | .name = "hix5hd2-sata-phy", | ||
183 | .owner = THIS_MODULE, | ||
184 | .of_match_table = hix5hd2_sata_phy_of_match, | ||
185 | } | ||
186 | }; | ||
187 | module_platform_driver(hix5hd2_sata_phy_driver); | ||
188 | |||
189 | MODULE_AUTHOR("Jiancheng Xue <xuejiancheng@huawei.com>"); | ||
190 | MODULE_DESCRIPTION("HISILICON HIX5HD2 SATA PHY driver"); | ||
191 | MODULE_ALIAS("platform:hix5hd2-sata-phy"); | ||
192 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/phy/phy-miphy365x.c b/drivers/phy/phy-miphy365x.c new file mode 100644 index 000000000000..e111baf187ce --- /dev/null +++ b/drivers/phy/phy-miphy365x.c | |||
@@ -0,0 +1,636 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014 STMicroelectronics – All Rights Reserved | ||
3 | * | ||
4 | * STMicroelectronics PHY driver MiPHY365 (for SoC STiH416). | ||
5 | * | ||
6 | * Authors: Alexandre Torgue <alexandre.torgue@st.com> | ||
7 | * Lee Jones <lee.jones@linaro.org> | ||
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 | * | ||
13 | */ | ||
14 | |||
15 | #include <linux/platform_device.h> | ||
16 | #include <linux/io.h> | ||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/module.h> | ||
19 | #include <linux/of.h> | ||
20 | #include <linux/of_platform.h> | ||
21 | #include <linux/of_address.h> | ||
22 | #include <linux/clk.h> | ||
23 | #include <linux/phy/phy.h> | ||
24 | #include <linux/delay.h> | ||
25 | #include <linux/mfd/syscon.h> | ||
26 | #include <linux/regmap.h> | ||
27 | |||
28 | #include <dt-bindings/phy/phy-miphy365x.h> | ||
29 | |||
30 | #define HFC_TIMEOUT 100 | ||
31 | |||
32 | #define SYSCFG_SELECT_SATA_MASK BIT(1) | ||
33 | #define SYSCFG_SELECT_SATA_POS 1 | ||
34 | |||
35 | /* MiPHY365x register definitions */ | ||
36 | #define RESET_REG 0x00 | ||
37 | #define RST_PLL BIT(1) | ||
38 | #define RST_PLL_CAL BIT(2) | ||
39 | #define RST_RX BIT(4) | ||
40 | #define RST_MACRO BIT(7) | ||
41 | |||
42 | #define STATUS_REG 0x01 | ||
43 | #define IDLL_RDY BIT(0) | ||
44 | #define PLL_RDY BIT(1) | ||
45 | #define DES_BIT_LOCK BIT(2) | ||
46 | #define DES_SYMBOL_LOCK BIT(3) | ||
47 | |||
48 | #define CTRL_REG 0x02 | ||
49 | #define TERM_EN BIT(0) | ||
50 | #define PCI_EN BIT(2) | ||
51 | #define DES_BIT_LOCK_EN BIT(3) | ||
52 | #define TX_POL BIT(5) | ||
53 | |||
54 | #define INT_CTRL_REG 0x03 | ||
55 | |||
56 | #define BOUNDARY1_REG 0x10 | ||
57 | #define SPDSEL_SEL BIT(0) | ||
58 | |||
59 | #define BOUNDARY3_REG 0x12 | ||
60 | #define TX_SPDSEL_GEN1_VAL 0 | ||
61 | #define TX_SPDSEL_GEN2_VAL 0x01 | ||
62 | #define TX_SPDSEL_GEN3_VAL 0x02 | ||
63 | #define RX_SPDSEL_GEN1_VAL 0 | ||
64 | #define RX_SPDSEL_GEN2_VAL (0x01 << 3) | ||
65 | #define RX_SPDSEL_GEN3_VAL (0x02 << 3) | ||
66 | |||
67 | #define PCIE_REG 0x16 | ||
68 | |||
69 | #define BUF_SEL_REG 0x20 | ||
70 | #define CONF_GEN_SEL_GEN3 0x02 | ||
71 | #define CONF_GEN_SEL_GEN2 0x01 | ||
72 | #define PD_VDDTFILTER BIT(4) | ||
73 | |||
74 | #define TXBUF1_REG 0x21 | ||
75 | #define SWING_VAL 0x04 | ||
76 | #define SWING_VAL_GEN1 0x03 | ||
77 | #define PREEMPH_VAL (0x3 << 5) | ||
78 | |||
79 | #define TXBUF2_REG 0x22 | ||
80 | #define TXSLEW_VAL 0x2 | ||
81 | #define TXSLEW_VAL_GEN1 0x4 | ||
82 | |||
83 | #define RXBUF_OFFSET_CTRL_REG 0x23 | ||
84 | |||
85 | #define RXBUF_REG 0x25 | ||
86 | #define SDTHRES_VAL 0x01 | ||
87 | #define EQ_ON3 (0x03 << 4) | ||
88 | #define EQ_ON1 (0x01 << 4) | ||
89 | |||
90 | #define COMP_CTRL1_REG 0x40 | ||
91 | #define START_COMSR BIT(0) | ||
92 | #define START_COMZC BIT(1) | ||
93 | #define COMSR_DONE BIT(2) | ||
94 | #define COMZC_DONE BIT(3) | ||
95 | #define COMP_AUTO_LOAD BIT(4) | ||
96 | |||
97 | #define COMP_CTRL2_REG 0x41 | ||
98 | #define COMP_2MHZ_RAT_GEN1 0x1e | ||
99 | #define COMP_2MHZ_RAT 0xf | ||
100 | |||
101 | #define COMP_CTRL3_REG 0x42 | ||
102 | #define COMSR_COMP_REF 0x33 | ||
103 | |||
104 | #define COMP_IDLL_REG 0x47 | ||
105 | #define COMZC_IDLL 0x2a | ||
106 | |||
107 | #define PLL_CTRL1_REG 0x50 | ||
108 | #define PLL_START_CAL BIT(0) | ||
109 | #define BUF_EN BIT(2) | ||
110 | #define SYNCHRO_TX BIT(3) | ||
111 | #define SSC_EN BIT(6) | ||
112 | #define CONFIG_PLL BIT(7) | ||
113 | |||
114 | #define PLL_CTRL2_REG 0x51 | ||
115 | #define BYPASS_PLL_CAL BIT(1) | ||
116 | |||
117 | #define PLL_RAT_REG 0x52 | ||
118 | |||
119 | #define PLL_SSC_STEP_MSB_REG 0x56 | ||
120 | #define PLL_SSC_STEP_MSB_VAL 0x03 | ||
121 | |||
122 | #define PLL_SSC_STEP_LSB_REG 0x57 | ||
123 | #define PLL_SSC_STEP_LSB_VAL 0x63 | ||
124 | |||
125 | #define PLL_SSC_PER_MSB_REG 0x58 | ||
126 | #define PLL_SSC_PER_MSB_VAL 0 | ||
127 | |||
128 | #define PLL_SSC_PER_LSB_REG 0x59 | ||
129 | #define PLL_SSC_PER_LSB_VAL 0xf1 | ||
130 | |||
131 | #define IDLL_TEST_REG 0x72 | ||
132 | #define START_CLK_HF BIT(6) | ||
133 | |||
134 | #define DES_BITLOCK_REG 0x86 | ||
135 | #define BIT_LOCK_LEVEL 0x01 | ||
136 | #define BIT_LOCK_CNT_512 (0x03 << 5) | ||
137 | |||
138 | struct miphy365x_phy { | ||
139 | struct phy *phy; | ||
140 | void __iomem *base; | ||
141 | bool pcie_tx_pol_inv; | ||
142 | bool sata_tx_pol_inv; | ||
143 | u32 sata_gen; | ||
144 | u64 ctrlreg; | ||
145 | u8 type; | ||
146 | }; | ||
147 | |||
148 | struct miphy365x_dev { | ||
149 | struct device *dev; | ||
150 | struct regmap *regmap; | ||
151 | struct mutex miphy_mutex; | ||
152 | struct miphy365x_phy **phys; | ||
153 | }; | ||
154 | |||
155 | /* | ||
156 | * These values are represented in Device tree. They are considered to be ABI | ||
157 | * and although they can be extended any existing values must not change. | ||
158 | */ | ||
159 | enum miphy_sata_gen { | ||
160 | SATA_GEN1 = 1, | ||
161 | SATA_GEN2, | ||
162 | SATA_GEN3 | ||
163 | }; | ||
164 | |||
165 | static u8 rx_tx_spd[] = { | ||
166 | TX_SPDSEL_GEN1_VAL | RX_SPDSEL_GEN1_VAL, | ||
167 | TX_SPDSEL_GEN2_VAL | RX_SPDSEL_GEN2_VAL, | ||
168 | TX_SPDSEL_GEN3_VAL | RX_SPDSEL_GEN3_VAL | ||
169 | }; | ||
170 | |||
171 | /* | ||
172 | * This function selects the system configuration, | ||
173 | * either two SATA, one SATA and one PCIe, or two PCIe lanes. | ||
174 | */ | ||
175 | static int miphy365x_set_path(struct miphy365x_phy *miphy_phy, | ||
176 | struct miphy365x_dev *miphy_dev) | ||
177 | { | ||
178 | bool sata = (miphy_phy->type == MIPHY_TYPE_SATA); | ||
179 | |||
180 | return regmap_update_bits(miphy_dev->regmap, | ||
181 | (unsigned int)miphy_phy->ctrlreg, | ||
182 | SYSCFG_SELECT_SATA_MASK, | ||
183 | sata << SYSCFG_SELECT_SATA_POS); | ||
184 | } | ||
185 | |||
186 | static int miphy365x_init_pcie_port(struct miphy365x_phy *miphy_phy, | ||
187 | struct miphy365x_dev *miphy_dev) | ||
188 | { | ||
189 | u8 val; | ||
190 | |||
191 | if (miphy_phy->pcie_tx_pol_inv) { | ||
192 | /* Invert Tx polarity and clear pci_txdetect_pol bit */ | ||
193 | val = TERM_EN | PCI_EN | DES_BIT_LOCK_EN | TX_POL; | ||
194 | writeb_relaxed(val, miphy_phy->base + CTRL_REG); | ||
195 | writeb_relaxed(0x00, miphy_phy->base + PCIE_REG); | ||
196 | } | ||
197 | |||
198 | return 0; | ||
199 | } | ||
200 | |||
201 | static inline int miphy365x_hfc_not_rdy(struct miphy365x_phy *miphy_phy, | ||
202 | struct miphy365x_dev *miphy_dev) | ||
203 | { | ||
204 | unsigned long timeout = jiffies + msecs_to_jiffies(HFC_TIMEOUT); | ||
205 | u8 mask = IDLL_RDY | PLL_RDY; | ||
206 | u8 regval; | ||
207 | |||
208 | do { | ||
209 | regval = readb_relaxed(miphy_phy->base + STATUS_REG); | ||
210 | if (!(regval & mask)) | ||
211 | return 0; | ||
212 | |||
213 | usleep_range(2000, 2500); | ||
214 | } while (time_before(jiffies, timeout)); | ||
215 | |||
216 | dev_err(miphy_dev->dev, "HFC ready timeout!\n"); | ||
217 | return -EBUSY; | ||
218 | } | ||
219 | |||
220 | static inline int miphy365x_rdy(struct miphy365x_phy *miphy_phy, | ||
221 | struct miphy365x_dev *miphy_dev) | ||
222 | { | ||
223 | unsigned long timeout = jiffies + msecs_to_jiffies(HFC_TIMEOUT); | ||
224 | u8 mask = IDLL_RDY | PLL_RDY; | ||
225 | u8 regval; | ||
226 | |||
227 | do { | ||
228 | regval = readb_relaxed(miphy_phy->base + STATUS_REG); | ||
229 | if ((regval & mask) == mask) | ||
230 | return 0; | ||
231 | |||
232 | usleep_range(2000, 2500); | ||
233 | } while (time_before(jiffies, timeout)); | ||
234 | |||
235 | dev_err(miphy_dev->dev, "PHY not ready timeout!\n"); | ||
236 | return -EBUSY; | ||
237 | } | ||
238 | |||
239 | static inline void miphy365x_set_comp(struct miphy365x_phy *miphy_phy, | ||
240 | struct miphy365x_dev *miphy_dev) | ||
241 | { | ||
242 | u8 val, mask; | ||
243 | |||
244 | if (miphy_phy->sata_gen == SATA_GEN1) | ||
245 | writeb_relaxed(COMP_2MHZ_RAT_GEN1, | ||
246 | miphy_phy->base + COMP_CTRL2_REG); | ||
247 | else | ||
248 | writeb_relaxed(COMP_2MHZ_RAT, | ||
249 | miphy_phy->base + COMP_CTRL2_REG); | ||
250 | |||
251 | if (miphy_phy->sata_gen != SATA_GEN3) { | ||
252 | writeb_relaxed(COMSR_COMP_REF, | ||
253 | miphy_phy->base + COMP_CTRL3_REG); | ||
254 | /* | ||
255 | * Force VCO current to value defined by address 0x5A | ||
256 | * and disable PCIe100Mref bit | ||
257 | * Enable auto load compensation for pll_i_bias | ||
258 | */ | ||
259 | writeb_relaxed(BYPASS_PLL_CAL, miphy_phy->base + PLL_CTRL2_REG); | ||
260 | writeb_relaxed(COMZC_IDLL, miphy_phy->base + COMP_IDLL_REG); | ||
261 | } | ||
262 | |||
263 | /* | ||
264 | * Force restart compensation and enable auto load | ||
265 | * for Comzc_Tx, Comzc_Rx and Comsr on macro | ||
266 | */ | ||
267 | val = START_COMSR | START_COMZC | COMP_AUTO_LOAD; | ||
268 | writeb_relaxed(val, miphy_phy->base + COMP_CTRL1_REG); | ||
269 | |||
270 | mask = COMSR_DONE | COMZC_DONE; | ||
271 | while ((readb_relaxed(miphy_phy->base + COMP_CTRL1_REG) & mask) != mask) | ||
272 | cpu_relax(); | ||
273 | } | ||
274 | |||
275 | static inline void miphy365x_set_ssc(struct miphy365x_phy *miphy_phy, | ||
276 | struct miphy365x_dev *miphy_dev) | ||
277 | { | ||
278 | u8 val; | ||
279 | |||
280 | /* | ||
281 | * SSC Settings. SSC will be enabled through Link | ||
282 | * SSC Ampl. = 0.4% | ||
283 | * SSC Freq = 31KHz | ||
284 | */ | ||
285 | writeb_relaxed(PLL_SSC_STEP_MSB_VAL, | ||
286 | miphy_phy->base + PLL_SSC_STEP_MSB_REG); | ||
287 | writeb_relaxed(PLL_SSC_STEP_LSB_VAL, | ||
288 | miphy_phy->base + PLL_SSC_STEP_LSB_REG); | ||
289 | writeb_relaxed(PLL_SSC_PER_MSB_VAL, | ||
290 | miphy_phy->base + PLL_SSC_PER_MSB_REG); | ||
291 | writeb_relaxed(PLL_SSC_PER_LSB_VAL, | ||
292 | miphy_phy->base + PLL_SSC_PER_LSB_REG); | ||
293 | |||
294 | /* SSC Settings complete */ | ||
295 | if (miphy_phy->sata_gen == SATA_GEN1) { | ||
296 | val = PLL_START_CAL | BUF_EN | SYNCHRO_TX | CONFIG_PLL; | ||
297 | writeb_relaxed(val, miphy_phy->base + PLL_CTRL1_REG); | ||
298 | } else { | ||
299 | val = SSC_EN | PLL_START_CAL | BUF_EN | SYNCHRO_TX | CONFIG_PLL; | ||
300 | writeb_relaxed(val, miphy_phy->base + PLL_CTRL1_REG); | ||
301 | } | ||
302 | } | ||
303 | |||
304 | static int miphy365x_init_sata_port(struct miphy365x_phy *miphy_phy, | ||
305 | struct miphy365x_dev *miphy_dev) | ||
306 | { | ||
307 | int ret; | ||
308 | u8 val; | ||
309 | |||
310 | /* | ||
311 | * Force PHY macro reset, PLL calibration reset, PLL reset | ||
312 | * and assert Deserializer Reset | ||
313 | */ | ||
314 | val = RST_PLL | RST_PLL_CAL | RST_RX | RST_MACRO; | ||
315 | writeb_relaxed(val, miphy_phy->base + RESET_REG); | ||
316 | |||
317 | if (miphy_phy->sata_tx_pol_inv) | ||
318 | writeb_relaxed(TX_POL, miphy_phy->base + CTRL_REG); | ||
319 | |||
320 | /* | ||
321 | * Force macro1 to use rx_lspd, tx_lspd | ||
322 | * Force Rx_Clock on first I-DLL phase | ||
323 | * Force Des in HP mode on macro, rx_lspd, tx_lspd for Gen2/3 | ||
324 | */ | ||
325 | writeb_relaxed(SPDSEL_SEL, miphy_phy->base + BOUNDARY1_REG); | ||
326 | writeb_relaxed(START_CLK_HF, miphy_phy->base + IDLL_TEST_REG); | ||
327 | val = rx_tx_spd[miphy_phy->sata_gen]; | ||
328 | writeb_relaxed(val, miphy_phy->base + BOUNDARY3_REG); | ||
329 | |||
330 | /* Wait for HFC_READY = 0 */ | ||
331 | ret = miphy365x_hfc_not_rdy(miphy_phy, miphy_dev); | ||
332 | if (ret) | ||
333 | return ret; | ||
334 | |||
335 | /* Compensation Recalibration */ | ||
336 | miphy365x_set_comp(miphy_phy, miphy_dev); | ||
337 | |||
338 | switch (miphy_phy->sata_gen) { | ||
339 | case SATA_GEN3: | ||
340 | /* | ||
341 | * TX Swing target 550-600mv peak to peak diff | ||
342 | * Tx Slew target 90-110ps rising/falling time | ||
343 | * Rx Eq ON3, Sigdet threshold SDTH1 | ||
344 | */ | ||
345 | val = PD_VDDTFILTER | CONF_GEN_SEL_GEN3; | ||
346 | writeb_relaxed(val, miphy_phy->base + BUF_SEL_REG); | ||
347 | val = SWING_VAL | PREEMPH_VAL; | ||
348 | writeb_relaxed(val, miphy_phy->base + TXBUF1_REG); | ||
349 | writeb_relaxed(TXSLEW_VAL, miphy_phy->base + TXBUF2_REG); | ||
350 | writeb_relaxed(0x00, miphy_phy->base + RXBUF_OFFSET_CTRL_REG); | ||
351 | val = SDTHRES_VAL | EQ_ON3; | ||
352 | writeb_relaxed(val, miphy_phy->base + RXBUF_REG); | ||
353 | break; | ||
354 | case SATA_GEN2: | ||
355 | /* | ||
356 | * conf gen sel=0x1 to program Gen2 banked registers | ||
357 | * VDDT filter ON | ||
358 | * Tx Swing target 550-600mV peak-to-peak diff | ||
359 | * Tx Slew target 90-110 ps rising/falling time | ||
360 | * RX Equalization ON1, Sigdet threshold SDTH1 | ||
361 | */ | ||
362 | writeb_relaxed(CONF_GEN_SEL_GEN2, | ||
363 | miphy_phy->base + BUF_SEL_REG); | ||
364 | writeb_relaxed(SWING_VAL, miphy_phy->base + TXBUF1_REG); | ||
365 | writeb_relaxed(TXSLEW_VAL, miphy_phy->base + TXBUF2_REG); | ||
366 | val = SDTHRES_VAL | EQ_ON1; | ||
367 | writeb_relaxed(val, miphy_phy->base + RXBUF_REG); | ||
368 | break; | ||
369 | case SATA_GEN1: | ||
370 | /* | ||
371 | * conf gen sel = 00b to program Gen1 banked registers | ||
372 | * VDDT filter ON | ||
373 | * Tx Swing target 500-550mV peak-to-peak diff | ||
374 | * Tx Slew target120-140 ps rising/falling time | ||
375 | */ | ||
376 | writeb_relaxed(PD_VDDTFILTER, miphy_phy->base + BUF_SEL_REG); | ||
377 | writeb_relaxed(SWING_VAL_GEN1, miphy_phy->base + TXBUF1_REG); | ||
378 | writeb_relaxed(TXSLEW_VAL_GEN1, miphy_phy->base + TXBUF2_REG); | ||
379 | break; | ||
380 | default: | ||
381 | break; | ||
382 | } | ||
383 | |||
384 | /* Force Macro1 in partial mode & release pll cal reset */ | ||
385 | writeb_relaxed(RST_RX, miphy_phy->base + RESET_REG); | ||
386 | usleep_range(100, 150); | ||
387 | |||
388 | miphy365x_set_ssc(miphy_phy, miphy_dev); | ||
389 | |||
390 | /* Wait for phy_ready */ | ||
391 | ret = miphy365x_rdy(miphy_phy, miphy_dev); | ||
392 | if (ret) | ||
393 | return ret; | ||
394 | |||
395 | /* | ||
396 | * Enable macro1 to use rx_lspd & tx_lspd | ||
397 | * Release Rx_Clock on first I-DLL phase on macro1 | ||
398 | * Assert deserializer reset | ||
399 | * des_bit_lock_en is set | ||
400 | * bit lock detection strength | ||
401 | * Deassert deserializer reset | ||
402 | */ | ||
403 | writeb_relaxed(0x00, miphy_phy->base + BOUNDARY1_REG); | ||
404 | writeb_relaxed(0x00, miphy_phy->base + IDLL_TEST_REG); | ||
405 | writeb_relaxed(RST_RX, miphy_phy->base + RESET_REG); | ||
406 | val = miphy_phy->sata_tx_pol_inv ? | ||
407 | (TX_POL | DES_BIT_LOCK_EN) : DES_BIT_LOCK_EN; | ||
408 | writeb_relaxed(val, miphy_phy->base + CTRL_REG); | ||
409 | |||
410 | val = BIT_LOCK_CNT_512 | BIT_LOCK_LEVEL; | ||
411 | writeb_relaxed(val, miphy_phy->base + DES_BITLOCK_REG); | ||
412 | writeb_relaxed(0x00, miphy_phy->base + RESET_REG); | ||
413 | |||
414 | return 0; | ||
415 | } | ||
416 | |||
417 | static int miphy365x_init(struct phy *phy) | ||
418 | { | ||
419 | struct miphy365x_phy *miphy_phy = phy_get_drvdata(phy); | ||
420 | struct miphy365x_dev *miphy_dev = dev_get_drvdata(phy->dev.parent); | ||
421 | int ret = 0; | ||
422 | |||
423 | mutex_lock(&miphy_dev->miphy_mutex); | ||
424 | |||
425 | ret = miphy365x_set_path(miphy_phy, miphy_dev); | ||
426 | if (ret) { | ||
427 | mutex_unlock(&miphy_dev->miphy_mutex); | ||
428 | return ret; | ||
429 | } | ||
430 | |||
431 | /* Initialise Miphy for PCIe or SATA */ | ||
432 | if (miphy_phy->type == MIPHY_TYPE_PCIE) | ||
433 | ret = miphy365x_init_pcie_port(miphy_phy, miphy_dev); | ||
434 | else | ||
435 | ret = miphy365x_init_sata_port(miphy_phy, miphy_dev); | ||
436 | |||
437 | mutex_unlock(&miphy_dev->miphy_mutex); | ||
438 | |||
439 | return ret; | ||
440 | } | ||
441 | |||
442 | int miphy365x_get_addr(struct device *dev, struct miphy365x_phy *miphy_phy, | ||
443 | int index) | ||
444 | { | ||
445 | struct device_node *phynode = miphy_phy->phy->dev.of_node; | ||
446 | const char *name; | ||
447 | const __be32 *taddr; | ||
448 | int type = miphy_phy->type; | ||
449 | int ret; | ||
450 | |||
451 | ret = of_property_read_string_index(phynode, "reg-names", index, &name); | ||
452 | if (ret) { | ||
453 | dev_err(dev, "no reg-names property not found\n"); | ||
454 | return ret; | ||
455 | } | ||
456 | |||
457 | if (!strncmp(name, "syscfg", 6)) { | ||
458 | taddr = of_get_address(phynode, index, NULL, NULL); | ||
459 | if (!taddr) { | ||
460 | dev_err(dev, "failed to fetch syscfg address\n"); | ||
461 | return -EINVAL; | ||
462 | } | ||
463 | |||
464 | miphy_phy->ctrlreg = of_translate_address(phynode, taddr); | ||
465 | if (miphy_phy->ctrlreg == OF_BAD_ADDR) { | ||
466 | dev_err(dev, "failed to translate syscfg address\n"); | ||
467 | return -EINVAL; | ||
468 | } | ||
469 | |||
470 | return 0; | ||
471 | } | ||
472 | |||
473 | if (!((!strncmp(name, "sata", 4) && type == MIPHY_TYPE_SATA) || | ||
474 | (!strncmp(name, "pcie", 4) && type == MIPHY_TYPE_PCIE))) | ||
475 | return 0; | ||
476 | |||
477 | miphy_phy->base = of_iomap(phynode, index); | ||
478 | if (!miphy_phy->base) { | ||
479 | dev_err(dev, "Failed to map %s\n", phynode->full_name); | ||
480 | return -EINVAL; | ||
481 | } | ||
482 | |||
483 | return 0; | ||
484 | } | ||
485 | |||
486 | static struct phy *miphy365x_xlate(struct device *dev, | ||
487 | struct of_phandle_args *args) | ||
488 | { | ||
489 | struct miphy365x_dev *miphy_dev = dev_get_drvdata(dev); | ||
490 | struct miphy365x_phy *miphy_phy = NULL; | ||
491 | struct device_node *phynode = args->np; | ||
492 | int ret, index; | ||
493 | |||
494 | if (!of_device_is_available(phynode)) { | ||
495 | dev_warn(dev, "Requested PHY is disabled\n"); | ||
496 | return ERR_PTR(-ENODEV); | ||
497 | } | ||
498 | |||
499 | if (args->args_count != 1) { | ||
500 | dev_err(dev, "Invalid number of cells in 'phy' property\n"); | ||
501 | return ERR_PTR(-EINVAL); | ||
502 | } | ||
503 | |||
504 | for (index = 0; index < of_get_child_count(dev->of_node); index++) | ||
505 | if (phynode == miphy_dev->phys[index]->phy->dev.of_node) { | ||
506 | miphy_phy = miphy_dev->phys[index]; | ||
507 | break; | ||
508 | } | ||
509 | |||
510 | if (!miphy_phy) { | ||
511 | dev_err(dev, "Failed to find appropriate phy\n"); | ||
512 | return ERR_PTR(-EINVAL); | ||
513 | } | ||
514 | |||
515 | miphy_phy->type = args->args[0]; | ||
516 | |||
517 | if (!(miphy_phy->type == MIPHY_TYPE_SATA || | ||
518 | miphy_phy->type == MIPHY_TYPE_PCIE)) { | ||
519 | dev_err(dev, "Unsupported device type: %d\n", miphy_phy->type); | ||
520 | return ERR_PTR(-EINVAL); | ||
521 | } | ||
522 | |||
523 | /* Each port handles SATA and PCIE - third entry is always sysconf. */ | ||
524 | for (index = 0; index < 3; index++) { | ||
525 | ret = miphy365x_get_addr(dev, miphy_phy, index); | ||
526 | if (ret < 0) | ||
527 | return ERR_PTR(ret); | ||
528 | } | ||
529 | |||
530 | return miphy_phy->phy; | ||
531 | } | ||
532 | |||
533 | static struct phy_ops miphy365x_ops = { | ||
534 | .init = miphy365x_init, | ||
535 | .owner = THIS_MODULE, | ||
536 | }; | ||
537 | |||
538 | static int miphy365x_of_probe(struct device_node *phynode, | ||
539 | struct miphy365x_phy *miphy_phy) | ||
540 | { | ||
541 | of_property_read_u32(phynode, "st,sata-gen", &miphy_phy->sata_gen); | ||
542 | if (!miphy_phy->sata_gen) | ||
543 | miphy_phy->sata_gen = SATA_GEN1; | ||
544 | |||
545 | miphy_phy->pcie_tx_pol_inv = | ||
546 | of_property_read_bool(phynode, "st,pcie-tx-pol-inv"); | ||
547 | |||
548 | miphy_phy->sata_tx_pol_inv = | ||
549 | of_property_read_bool(phynode, "st,sata-tx-pol-inv"); | ||
550 | |||
551 | return 0; | ||
552 | } | ||
553 | |||
554 | static int miphy365x_probe(struct platform_device *pdev) | ||
555 | { | ||
556 | struct device_node *child, *np = pdev->dev.of_node; | ||
557 | struct miphy365x_dev *miphy_dev; | ||
558 | struct phy_provider *provider; | ||
559 | struct phy *phy; | ||
560 | int chancount, port = 0; | ||
561 | int ret; | ||
562 | |||
563 | miphy_dev = devm_kzalloc(&pdev->dev, sizeof(*miphy_dev), GFP_KERNEL); | ||
564 | if (!miphy_dev) | ||
565 | return -ENOMEM; | ||
566 | |||
567 | chancount = of_get_child_count(np); | ||
568 | miphy_dev->phys = devm_kzalloc(&pdev->dev, sizeof(phy) * chancount, | ||
569 | GFP_KERNEL); | ||
570 | if (!miphy_dev->phys) | ||
571 | return -ENOMEM; | ||
572 | |||
573 | miphy_dev->regmap = syscon_regmap_lookup_by_phandle(np, "st,syscfg"); | ||
574 | if (IS_ERR(miphy_dev->regmap)) { | ||
575 | dev_err(miphy_dev->dev, "No syscfg phandle specified\n"); | ||
576 | return PTR_ERR(miphy_dev->regmap); | ||
577 | } | ||
578 | |||
579 | miphy_dev->dev = &pdev->dev; | ||
580 | |||
581 | dev_set_drvdata(&pdev->dev, miphy_dev); | ||
582 | |||
583 | mutex_init(&miphy_dev->miphy_mutex); | ||
584 | |||
585 | for_each_child_of_node(np, child) { | ||
586 | struct miphy365x_phy *miphy_phy; | ||
587 | |||
588 | miphy_phy = devm_kzalloc(&pdev->dev, sizeof(*miphy_phy), | ||
589 | GFP_KERNEL); | ||
590 | if (!miphy_phy) | ||
591 | return -ENOMEM; | ||
592 | |||
593 | miphy_dev->phys[port] = miphy_phy; | ||
594 | |||
595 | phy = devm_phy_create(&pdev->dev, child, &miphy365x_ops, NULL); | ||
596 | if (IS_ERR(phy)) { | ||
597 | dev_err(&pdev->dev, "failed to create PHY\n"); | ||
598 | return PTR_ERR(phy); | ||
599 | } | ||
600 | |||
601 | miphy_dev->phys[port]->phy = phy; | ||
602 | |||
603 | ret = miphy365x_of_probe(child, miphy_phy); | ||
604 | if (ret) | ||
605 | return ret; | ||
606 | |||
607 | phy_set_drvdata(phy, miphy_dev->phys[port]); | ||
608 | port++; | ||
609 | } | ||
610 | |||
611 | provider = devm_of_phy_provider_register(&pdev->dev, miphy365x_xlate); | ||
612 | if (IS_ERR(provider)) | ||
613 | return PTR_ERR(provider); | ||
614 | |||
615 | return 0; | ||
616 | } | ||
617 | |||
618 | static const struct of_device_id miphy365x_of_match[] = { | ||
619 | { .compatible = "st,miphy365x-phy", }, | ||
620 | { }, | ||
621 | }; | ||
622 | MODULE_DEVICE_TABLE(of, miphy365x_of_match); | ||
623 | |||
624 | static struct platform_driver miphy365x_driver = { | ||
625 | .probe = miphy365x_probe, | ||
626 | .driver = { | ||
627 | .name = "miphy365x-phy", | ||
628 | .owner = THIS_MODULE, | ||
629 | .of_match_table = miphy365x_of_match, | ||
630 | } | ||
631 | }; | ||
632 | module_platform_driver(miphy365x_driver); | ||
633 | |||
634 | MODULE_AUTHOR("Alexandre Torgue <alexandre.torgue@st.com>"); | ||
635 | MODULE_DESCRIPTION("STMicroelectronics miphy365x driver"); | ||
636 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/phy/phy-mvebu-sata.c b/drivers/phy/phy-mvebu-sata.c index d70ecd6a1b3f..cc3c0e166daf 100644 --- a/drivers/phy/phy-mvebu-sata.c +++ b/drivers/phy/phy-mvebu-sata.c | |||
@@ -99,7 +99,7 @@ static int phy_mvebu_sata_probe(struct platform_device *pdev) | |||
99 | if (IS_ERR(priv->clk)) | 99 | if (IS_ERR(priv->clk)) |
100 | return PTR_ERR(priv->clk); | 100 | return PTR_ERR(priv->clk); |
101 | 101 | ||
102 | phy = devm_phy_create(&pdev->dev, &phy_mvebu_sata_ops, NULL); | 102 | phy = devm_phy_create(&pdev->dev, NULL, &phy_mvebu_sata_ops, NULL); |
103 | if (IS_ERR(phy)) | 103 | if (IS_ERR(phy)) |
104 | return PTR_ERR(phy); | 104 | return PTR_ERR(phy); |
105 | 105 | ||
diff --git a/drivers/phy/phy-omap-control.c b/drivers/phy/phy-omap-control.c index 311b4f9a5132..9487bf112267 100644 --- a/drivers/phy/phy-omap-control.c +++ b/drivers/phy/phy-omap-control.c | |||
@@ -27,6 +27,41 @@ | |||
27 | #include <linux/phy/omap_control_phy.h> | 27 | #include <linux/phy/omap_control_phy.h> |
28 | 28 | ||
29 | /** | 29 | /** |
30 | * omap_control_pcie_pcs - set the PCS delay count | ||
31 | * @dev: the control module device | ||
32 | * @id: index of the pcie PHY (should be 1 or 2) | ||
33 | * @delay: 8 bit delay value | ||
34 | */ | ||
35 | void omap_control_pcie_pcs(struct device *dev, u8 id, u8 delay) | ||
36 | { | ||
37 | u32 val; | ||
38 | struct omap_control_phy *control_phy; | ||
39 | |||
40 | if (IS_ERR(dev) || !dev) { | ||
41 | pr_err("%s: invalid device\n", __func__); | ||
42 | return; | ||
43 | } | ||
44 | |||
45 | control_phy = dev_get_drvdata(dev); | ||
46 | if (!control_phy) { | ||
47 | dev_err(dev, "%s: invalid control phy device\n", __func__); | ||
48 | return; | ||
49 | } | ||
50 | |||
51 | if (control_phy->type != OMAP_CTRL_TYPE_PCIE) { | ||
52 | dev_err(dev, "%s: unsupported operation\n", __func__); | ||
53 | return; | ||
54 | } | ||
55 | |||
56 | val = readl(control_phy->pcie_pcs); | ||
57 | val &= ~(OMAP_CTRL_PCIE_PCS_MASK << | ||
58 | (id * OMAP_CTRL_PCIE_PCS_DELAY_COUNT_SHIFT)); | ||
59 | val |= delay << (id * OMAP_CTRL_PCIE_PCS_DELAY_COUNT_SHIFT); | ||
60 | writel(val, control_phy->pcie_pcs); | ||
61 | } | ||
62 | EXPORT_SYMBOL_GPL(omap_control_pcie_pcs); | ||
63 | |||
64 | /** | ||
30 | * omap_control_phy_power - power on/off the phy using control module reg | 65 | * omap_control_phy_power - power on/off the phy using control module reg |
31 | * @dev: the control module device | 66 | * @dev: the control module device |
32 | * @on: 0 or 1, based on powering on or off the PHY | 67 | * @on: 0 or 1, based on powering on or off the PHY |
@@ -61,6 +96,7 @@ void omap_control_phy_power(struct device *dev, int on) | |||
61 | val |= OMAP_CTRL_DEV_PHY_PD; | 96 | val |= OMAP_CTRL_DEV_PHY_PD; |
62 | break; | 97 | break; |
63 | 98 | ||
99 | case OMAP_CTRL_TYPE_PCIE: | ||
64 | case OMAP_CTRL_TYPE_PIPE3: | 100 | case OMAP_CTRL_TYPE_PIPE3: |
65 | rate = clk_get_rate(control_phy->sys_clk); | 101 | rate = clk_get_rate(control_phy->sys_clk); |
66 | rate = rate/1000000; | 102 | rate = rate/1000000; |
@@ -211,6 +247,7 @@ EXPORT_SYMBOL_GPL(omap_control_usb_set_mode); | |||
211 | static const enum omap_control_phy_type otghs_data = OMAP_CTRL_TYPE_OTGHS; | 247 | static const enum omap_control_phy_type otghs_data = OMAP_CTRL_TYPE_OTGHS; |
212 | static const enum omap_control_phy_type usb2_data = OMAP_CTRL_TYPE_USB2; | 248 | static const enum omap_control_phy_type usb2_data = OMAP_CTRL_TYPE_USB2; |
213 | static const enum omap_control_phy_type pipe3_data = OMAP_CTRL_TYPE_PIPE3; | 249 | static const enum omap_control_phy_type pipe3_data = OMAP_CTRL_TYPE_PIPE3; |
250 | static const enum omap_control_phy_type pcie_data = OMAP_CTRL_TYPE_PCIE; | ||
214 | static const enum omap_control_phy_type dra7usb2_data = OMAP_CTRL_TYPE_DRA7USB2; | 251 | static const enum omap_control_phy_type dra7usb2_data = OMAP_CTRL_TYPE_DRA7USB2; |
215 | static const enum omap_control_phy_type am437usb2_data = OMAP_CTRL_TYPE_AM437USB2; | 252 | static const enum omap_control_phy_type am437usb2_data = OMAP_CTRL_TYPE_AM437USB2; |
216 | 253 | ||
@@ -228,6 +265,10 @@ static const struct of_device_id omap_control_phy_id_table[] = { | |||
228 | .data = &pipe3_data, | 265 | .data = &pipe3_data, |
229 | }, | 266 | }, |
230 | { | 267 | { |
268 | .compatible = "ti,control-phy-pcie", | ||
269 | .data = &pcie_data, | ||
270 | }, | ||
271 | { | ||
231 | .compatible = "ti,control-phy-usb2-dra7", | 272 | .compatible = "ti,control-phy-usb2-dra7", |
232 | .data = &dra7usb2_data, | 273 | .data = &dra7usb2_data, |
233 | }, | 274 | }, |
@@ -279,7 +320,8 @@ static int omap_control_phy_probe(struct platform_device *pdev) | |||
279 | } | 320 | } |
280 | } | 321 | } |
281 | 322 | ||
282 | if (control_phy->type == OMAP_CTRL_TYPE_PIPE3) { | 323 | if (control_phy->type == OMAP_CTRL_TYPE_PIPE3 || |
324 | control_phy->type == OMAP_CTRL_TYPE_PCIE) { | ||
283 | control_phy->sys_clk = devm_clk_get(control_phy->dev, | 325 | control_phy->sys_clk = devm_clk_get(control_phy->dev, |
284 | "sys_clkin"); | 326 | "sys_clkin"); |
285 | if (IS_ERR(control_phy->sys_clk)) { | 327 | if (IS_ERR(control_phy->sys_clk)) { |
@@ -288,6 +330,14 @@ static int omap_control_phy_probe(struct platform_device *pdev) | |||
288 | } | 330 | } |
289 | } | 331 | } |
290 | 332 | ||
333 | if (control_phy->type == OMAP_CTRL_TYPE_PCIE) { | ||
334 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, | ||
335 | "pcie_pcs"); | ||
336 | control_phy->pcie_pcs = devm_ioremap_resource(&pdev->dev, res); | ||
337 | if (IS_ERR(control_phy->pcie_pcs)) | ||
338 | return PTR_ERR(control_phy->pcie_pcs); | ||
339 | } | ||
340 | |||
291 | dev_set_drvdata(control_phy->dev, control_phy); | 341 | dev_set_drvdata(control_phy->dev, control_phy); |
292 | 342 | ||
293 | return 0; | 343 | return 0; |
diff --git a/drivers/phy/phy-omap-usb2.c b/drivers/phy/phy-omap-usb2.c index 7007c11fe07d..93d78359246c 100644 --- a/drivers/phy/phy-omap-usb2.c +++ b/drivers/phy/phy-omap-usb2.c | |||
@@ -233,8 +233,8 @@ static int omap_usb2_probe(struct platform_device *pdev) | |||
233 | if (phy_data->flags & OMAP_USB2_CALIBRATE_FALSE_DISCONNECT) { | 233 | if (phy_data->flags & OMAP_USB2_CALIBRATE_FALSE_DISCONNECT) { |
234 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 234 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
235 | phy->phy_base = devm_ioremap_resource(&pdev->dev, res); | 235 | phy->phy_base = devm_ioremap_resource(&pdev->dev, res); |
236 | if (!phy->phy_base) | 236 | if (IS_ERR(phy->phy_base)) |
237 | return -ENOMEM; | 237 | return PTR_ERR(phy->phy_base); |
238 | phy->flags |= OMAP_USB2_CALIBRATE_FALSE_DISCONNECT; | 238 | phy->flags |= OMAP_USB2_CALIBRATE_FALSE_DISCONNECT; |
239 | } | 239 | } |
240 | 240 | ||
@@ -262,18 +262,20 @@ static int omap_usb2_probe(struct platform_device *pdev) | |||
262 | otg->phy = &phy->phy; | 262 | otg->phy = &phy->phy; |
263 | 263 | ||
264 | platform_set_drvdata(pdev, phy); | 264 | platform_set_drvdata(pdev, phy); |
265 | pm_runtime_enable(phy->dev); | ||
266 | 265 | ||
267 | generic_phy = devm_phy_create(phy->dev, &ops, NULL); | 266 | generic_phy = devm_phy_create(phy->dev, NULL, &ops, NULL); |
268 | if (IS_ERR(generic_phy)) | 267 | if (IS_ERR(generic_phy)) |
269 | return PTR_ERR(generic_phy); | 268 | return PTR_ERR(generic_phy); |
270 | 269 | ||
271 | phy_set_drvdata(generic_phy, phy); | 270 | phy_set_drvdata(generic_phy, phy); |
272 | 271 | ||
272 | pm_runtime_enable(phy->dev); | ||
273 | phy_provider = devm_of_phy_provider_register(phy->dev, | 273 | phy_provider = devm_of_phy_provider_register(phy->dev, |
274 | of_phy_simple_xlate); | 274 | of_phy_simple_xlate); |
275 | if (IS_ERR(phy_provider)) | 275 | if (IS_ERR(phy_provider)) { |
276 | pm_runtime_disable(phy->dev); | ||
276 | return PTR_ERR(phy_provider); | 277 | return PTR_ERR(phy_provider); |
278 | } | ||
277 | 279 | ||
278 | phy->wkupclk = devm_clk_get(phy->dev, "wkupclk"); | 280 | phy->wkupclk = devm_clk_get(phy->dev, "wkupclk"); |
279 | if (IS_ERR(phy->wkupclk)) { | 281 | if (IS_ERR(phy->wkupclk)) { |
@@ -317,6 +319,7 @@ static int omap_usb2_remove(struct platform_device *pdev) | |||
317 | if (!IS_ERR(phy->optclk)) | 319 | if (!IS_ERR(phy->optclk)) |
318 | clk_unprepare(phy->optclk); | 320 | clk_unprepare(phy->optclk); |
319 | usb_remove_phy(&phy->phy); | 321 | usb_remove_phy(&phy->phy); |
322 | pm_runtime_disable(phy->dev); | ||
320 | 323 | ||
321 | return 0; | 324 | return 0; |
322 | } | 325 | } |
diff --git a/drivers/phy/phy-qcom-apq8064-sata.c b/drivers/phy/phy-qcom-apq8064-sata.c new file mode 100644 index 000000000000..b3ef7d805765 --- /dev/null +++ b/drivers/phy/phy-qcom-apq8064-sata.c | |||
@@ -0,0 +1,289 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2014, The Linux Foundation. All rights reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 and | ||
6 | * only version 2 as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, | ||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | * GNU General Public License for more details. | ||
12 | */ | ||
13 | |||
14 | #include <linux/io.h> | ||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/of.h> | ||
18 | #include <linux/time.h> | ||
19 | #include <linux/delay.h> | ||
20 | #include <linux/clk.h> | ||
21 | #include <linux/slab.h> | ||
22 | #include <linux/platform_device.h> | ||
23 | #include <linux/phy/phy.h> | ||
24 | |||
25 | /* PHY registers */ | ||
26 | #define UNIPHY_PLL_REFCLK_CFG 0x000 | ||
27 | #define UNIPHY_PLL_PWRGEN_CFG 0x014 | ||
28 | #define UNIPHY_PLL_GLB_CFG 0x020 | ||
29 | #define UNIPHY_PLL_SDM_CFG0 0x038 | ||
30 | #define UNIPHY_PLL_SDM_CFG1 0x03C | ||
31 | #define UNIPHY_PLL_SDM_CFG2 0x040 | ||
32 | #define UNIPHY_PLL_SDM_CFG3 0x044 | ||
33 | #define UNIPHY_PLL_SDM_CFG4 0x048 | ||
34 | #define UNIPHY_PLL_SSC_CFG0 0x04C | ||
35 | #define UNIPHY_PLL_SSC_CFG1 0x050 | ||
36 | #define UNIPHY_PLL_SSC_CFG2 0x054 | ||
37 | #define UNIPHY_PLL_SSC_CFG3 0x058 | ||
38 | #define UNIPHY_PLL_LKDET_CFG0 0x05C | ||
39 | #define UNIPHY_PLL_LKDET_CFG1 0x060 | ||
40 | #define UNIPHY_PLL_LKDET_CFG2 0x064 | ||
41 | #define UNIPHY_PLL_CAL_CFG0 0x06C | ||
42 | #define UNIPHY_PLL_CAL_CFG8 0x08C | ||
43 | #define UNIPHY_PLL_CAL_CFG9 0x090 | ||
44 | #define UNIPHY_PLL_CAL_CFG10 0x094 | ||
45 | #define UNIPHY_PLL_CAL_CFG11 0x098 | ||
46 | #define UNIPHY_PLL_STATUS 0x0C0 | ||
47 | |||
48 | #define SATA_PHY_SER_CTRL 0x100 | ||
49 | #define SATA_PHY_TX_DRIV_CTRL0 0x104 | ||
50 | #define SATA_PHY_TX_DRIV_CTRL1 0x108 | ||
51 | #define SATA_PHY_TX_IMCAL0 0x11C | ||
52 | #define SATA_PHY_TX_IMCAL2 0x124 | ||
53 | #define SATA_PHY_RX_IMCAL0 0x128 | ||
54 | #define SATA_PHY_EQUAL 0x13C | ||
55 | #define SATA_PHY_OOB_TERM 0x144 | ||
56 | #define SATA_PHY_CDR_CTRL0 0x148 | ||
57 | #define SATA_PHY_CDR_CTRL1 0x14C | ||
58 | #define SATA_PHY_CDR_CTRL2 0x150 | ||
59 | #define SATA_PHY_CDR_CTRL3 0x154 | ||
60 | #define SATA_PHY_PI_CTRL0 0x168 | ||
61 | #define SATA_PHY_POW_DWN_CTRL0 0x180 | ||
62 | #define SATA_PHY_POW_DWN_CTRL1 0x184 | ||
63 | #define SATA_PHY_TX_DATA_CTRL 0x188 | ||
64 | #define SATA_PHY_ALIGNP 0x1A4 | ||
65 | #define SATA_PHY_TX_IMCAL_STAT 0x1E4 | ||
66 | #define SATA_PHY_RX_IMCAL_STAT 0x1E8 | ||
67 | |||
68 | #define UNIPHY_PLL_LOCK BIT(0) | ||
69 | #define SATA_PHY_TX_CAL BIT(0) | ||
70 | #define SATA_PHY_RX_CAL BIT(0) | ||
71 | |||
72 | /* default timeout set to 1 sec */ | ||
73 | #define TIMEOUT_MS 10000 | ||
74 | #define DELAY_INTERVAL_US 100 | ||
75 | |||
76 | struct qcom_apq8064_sata_phy { | ||
77 | void __iomem *mmio; | ||
78 | struct clk *cfg_clk; | ||
79 | struct device *dev; | ||
80 | }; | ||
81 | |||
82 | /* Helper function to do poll and timeout */ | ||
83 | static int read_poll_timeout(void __iomem *addr, u32 mask) | ||
84 | { | ||
85 | unsigned long timeout = jiffies + msecs_to_jiffies(TIMEOUT_MS); | ||
86 | |||
87 | do { | ||
88 | if (readl_relaxed(addr) & mask) | ||
89 | return 0; | ||
90 | |||
91 | usleep_range(DELAY_INTERVAL_US, DELAY_INTERVAL_US + 50); | ||
92 | } while (!time_after(jiffies, timeout)); | ||
93 | |||
94 | return (readl_relaxed(addr) & mask) ? 0 : -ETIMEDOUT; | ||
95 | } | ||
96 | |||
97 | static int qcom_apq8064_sata_phy_init(struct phy *generic_phy) | ||
98 | { | ||
99 | struct qcom_apq8064_sata_phy *phy = phy_get_drvdata(generic_phy); | ||
100 | void __iomem *base = phy->mmio; | ||
101 | int ret = 0; | ||
102 | |||
103 | /* SATA phy initialization */ | ||
104 | writel_relaxed(0x01, base + SATA_PHY_SER_CTRL); | ||
105 | writel_relaxed(0xB1, base + SATA_PHY_POW_DWN_CTRL0); | ||
106 | /* Make sure the power down happens before power up */ | ||
107 | mb(); | ||
108 | usleep_range(10, 60); | ||
109 | |||
110 | writel_relaxed(0x01, base + SATA_PHY_POW_DWN_CTRL0); | ||
111 | writel_relaxed(0x3E, base + SATA_PHY_POW_DWN_CTRL1); | ||
112 | writel_relaxed(0x01, base + SATA_PHY_RX_IMCAL0); | ||
113 | writel_relaxed(0x01, base + SATA_PHY_TX_IMCAL0); | ||
114 | writel_relaxed(0x02, base + SATA_PHY_TX_IMCAL2); | ||
115 | |||
116 | /* Write UNIPHYPLL registers to configure PLL */ | ||
117 | writel_relaxed(0x04, base + UNIPHY_PLL_REFCLK_CFG); | ||
118 | writel_relaxed(0x00, base + UNIPHY_PLL_PWRGEN_CFG); | ||
119 | |||
120 | writel_relaxed(0x0A, base + UNIPHY_PLL_CAL_CFG0); | ||
121 | writel_relaxed(0xF3, base + UNIPHY_PLL_CAL_CFG8); | ||
122 | writel_relaxed(0x01, base + UNIPHY_PLL_CAL_CFG9); | ||
123 | writel_relaxed(0xED, base + UNIPHY_PLL_CAL_CFG10); | ||
124 | writel_relaxed(0x02, base + UNIPHY_PLL_CAL_CFG11); | ||
125 | |||
126 | writel_relaxed(0x36, base + UNIPHY_PLL_SDM_CFG0); | ||
127 | writel_relaxed(0x0D, base + UNIPHY_PLL_SDM_CFG1); | ||
128 | writel_relaxed(0xA3, base + UNIPHY_PLL_SDM_CFG2); | ||
129 | writel_relaxed(0xF0, base + UNIPHY_PLL_SDM_CFG3); | ||
130 | writel_relaxed(0x00, base + UNIPHY_PLL_SDM_CFG4); | ||
131 | |||
132 | writel_relaxed(0x19, base + UNIPHY_PLL_SSC_CFG0); | ||
133 | writel_relaxed(0xE1, base + UNIPHY_PLL_SSC_CFG1); | ||
134 | writel_relaxed(0x00, base + UNIPHY_PLL_SSC_CFG2); | ||
135 | writel_relaxed(0x11, base + UNIPHY_PLL_SSC_CFG3); | ||
136 | |||
137 | writel_relaxed(0x04, base + UNIPHY_PLL_LKDET_CFG0); | ||
138 | writel_relaxed(0xFF, base + UNIPHY_PLL_LKDET_CFG1); | ||
139 | |||
140 | writel_relaxed(0x02, base + UNIPHY_PLL_GLB_CFG); | ||
141 | /* make sure global config LDO power down happens before power up */ | ||
142 | mb(); | ||
143 | |||
144 | writel_relaxed(0x03, base + UNIPHY_PLL_GLB_CFG); | ||
145 | writel_relaxed(0x05, base + UNIPHY_PLL_LKDET_CFG2); | ||
146 | |||
147 | /* PLL Lock wait */ | ||
148 | ret = read_poll_timeout(base + UNIPHY_PLL_STATUS, UNIPHY_PLL_LOCK); | ||
149 | if (ret) { | ||
150 | dev_err(phy->dev, "poll timeout UNIPHY_PLL_STATUS\n"); | ||
151 | return ret; | ||
152 | } | ||
153 | |||
154 | /* TX Calibration */ | ||
155 | ret = read_poll_timeout(base + SATA_PHY_TX_IMCAL_STAT, SATA_PHY_TX_CAL); | ||
156 | if (ret) { | ||
157 | dev_err(phy->dev, "poll timeout SATA_PHY_TX_IMCAL_STAT\n"); | ||
158 | return ret; | ||
159 | } | ||
160 | |||
161 | /* RX Calibration */ | ||
162 | ret = read_poll_timeout(base + SATA_PHY_RX_IMCAL_STAT, SATA_PHY_RX_CAL); | ||
163 | if (ret) { | ||
164 | dev_err(phy->dev, "poll timeout SATA_PHY_RX_IMCAL_STAT\n"); | ||
165 | return ret; | ||
166 | } | ||
167 | |||
168 | /* SATA phy calibrated succesfully, power up to functional mode */ | ||
169 | writel_relaxed(0x3E, base + SATA_PHY_POW_DWN_CTRL1); | ||
170 | writel_relaxed(0x01, base + SATA_PHY_RX_IMCAL0); | ||
171 | writel_relaxed(0x01, base + SATA_PHY_TX_IMCAL0); | ||
172 | |||
173 | writel_relaxed(0x00, base + SATA_PHY_POW_DWN_CTRL1); | ||
174 | writel_relaxed(0x59, base + SATA_PHY_CDR_CTRL0); | ||
175 | writel_relaxed(0x04, base + SATA_PHY_CDR_CTRL1); | ||
176 | writel_relaxed(0x00, base + SATA_PHY_CDR_CTRL2); | ||
177 | writel_relaxed(0x00, base + SATA_PHY_PI_CTRL0); | ||
178 | writel_relaxed(0x00, base + SATA_PHY_CDR_CTRL3); | ||
179 | writel_relaxed(0x01, base + SATA_PHY_POW_DWN_CTRL0); | ||
180 | |||
181 | writel_relaxed(0x11, base + SATA_PHY_TX_DATA_CTRL); | ||
182 | writel_relaxed(0x43, base + SATA_PHY_ALIGNP); | ||
183 | writel_relaxed(0x04, base + SATA_PHY_OOB_TERM); | ||
184 | |||
185 | writel_relaxed(0x01, base + SATA_PHY_EQUAL); | ||
186 | writel_relaxed(0x09, base + SATA_PHY_TX_DRIV_CTRL0); | ||
187 | writel_relaxed(0x09, base + SATA_PHY_TX_DRIV_CTRL1); | ||
188 | |||
189 | return 0; | ||
190 | } | ||
191 | |||
192 | static int qcom_apq8064_sata_phy_exit(struct phy *generic_phy) | ||
193 | { | ||
194 | struct qcom_apq8064_sata_phy *phy = phy_get_drvdata(generic_phy); | ||
195 | void __iomem *base = phy->mmio; | ||
196 | |||
197 | /* Power down PHY */ | ||
198 | writel_relaxed(0xF8, base + SATA_PHY_POW_DWN_CTRL0); | ||
199 | writel_relaxed(0xFE, base + SATA_PHY_POW_DWN_CTRL1); | ||
200 | |||
201 | /* Power down PLL block */ | ||
202 | writel_relaxed(0x00, base + UNIPHY_PLL_GLB_CFG); | ||
203 | |||
204 | return 0; | ||
205 | } | ||
206 | |||
207 | static struct phy_ops qcom_apq8064_sata_phy_ops = { | ||
208 | .init = qcom_apq8064_sata_phy_init, | ||
209 | .exit = qcom_apq8064_sata_phy_exit, | ||
210 | .owner = THIS_MODULE, | ||
211 | }; | ||
212 | |||
213 | static int qcom_apq8064_sata_phy_probe(struct platform_device *pdev) | ||
214 | { | ||
215 | struct qcom_apq8064_sata_phy *phy; | ||
216 | struct device *dev = &pdev->dev; | ||
217 | struct resource *res; | ||
218 | struct phy_provider *phy_provider; | ||
219 | struct phy *generic_phy; | ||
220 | int ret; | ||
221 | |||
222 | phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL); | ||
223 | if (!phy) | ||
224 | return -ENOMEM; | ||
225 | |||
226 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
227 | phy->mmio = devm_ioremap_resource(dev, res); | ||
228 | if (IS_ERR(phy->mmio)) | ||
229 | return PTR_ERR(phy->mmio); | ||
230 | |||
231 | generic_phy = devm_phy_create(dev, NULL, &qcom_apq8064_sata_phy_ops, | ||
232 | NULL); | ||
233 | if (IS_ERR(generic_phy)) { | ||
234 | dev_err(dev, "%s: failed to create phy\n", __func__); | ||
235 | return PTR_ERR(generic_phy); | ||
236 | } | ||
237 | |||
238 | phy->dev = dev; | ||
239 | phy_set_drvdata(generic_phy, phy); | ||
240 | platform_set_drvdata(pdev, phy); | ||
241 | |||
242 | phy->cfg_clk = devm_clk_get(dev, "cfg"); | ||
243 | if (IS_ERR(phy->cfg_clk)) { | ||
244 | dev_err(dev, "Failed to get sata cfg clock\n"); | ||
245 | return PTR_ERR(phy->cfg_clk); | ||
246 | } | ||
247 | |||
248 | ret = clk_prepare_enable(phy->cfg_clk); | ||
249 | if (ret) | ||
250 | return ret; | ||
251 | |||
252 | phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); | ||
253 | if (IS_ERR(phy_provider)) { | ||
254 | clk_disable_unprepare(phy->cfg_clk); | ||
255 | dev_err(dev, "%s: failed to register phy\n", __func__); | ||
256 | return PTR_ERR(phy_provider); | ||
257 | } | ||
258 | |||
259 | return 0; | ||
260 | } | ||
261 | |||
262 | static int qcom_apq8064_sata_phy_remove(struct platform_device *pdev) | ||
263 | { | ||
264 | struct qcom_apq8064_sata_phy *phy = platform_get_drvdata(pdev); | ||
265 | |||
266 | clk_disable_unprepare(phy->cfg_clk); | ||
267 | |||
268 | return 0; | ||
269 | } | ||
270 | |||
271 | static const struct of_device_id qcom_apq8064_sata_phy_of_match[] = { | ||
272 | { .compatible = "qcom,apq8064-sata-phy" }, | ||
273 | { }, | ||
274 | }; | ||
275 | MODULE_DEVICE_TABLE(of, qcom_apq8064_sata_phy_of_match); | ||
276 | |||
277 | static struct platform_driver qcom_apq8064_sata_phy_driver = { | ||
278 | .probe = qcom_apq8064_sata_phy_probe, | ||
279 | .remove = qcom_apq8064_sata_phy_remove, | ||
280 | .driver = { | ||
281 | .name = "qcom-apq8064-sata-phy", | ||
282 | .owner = THIS_MODULE, | ||
283 | .of_match_table = qcom_apq8064_sata_phy_of_match, | ||
284 | } | ||
285 | }; | ||
286 | module_platform_driver(qcom_apq8064_sata_phy_driver); | ||
287 | |||
288 | MODULE_DESCRIPTION("QCOM apq8064 SATA PHY driver"); | ||
289 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/phy/phy-qcom-ipq806x-sata.c b/drivers/phy/phy-qcom-ipq806x-sata.c new file mode 100644 index 000000000000..909b5a87fc6a --- /dev/null +++ b/drivers/phy/phy-qcom-ipq806x-sata.c | |||
@@ -0,0 +1,211 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2014, The Linux Foundation. All rights reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 and | ||
6 | * only version 2 as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, | ||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | * GNU General Public License for more details. | ||
12 | */ | ||
13 | |||
14 | #include <linux/io.h> | ||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/of.h> | ||
18 | #include <linux/of_address.h> | ||
19 | #include <linux/time.h> | ||
20 | #include <linux/delay.h> | ||
21 | #include <linux/clk.h> | ||
22 | #include <linux/slab.h> | ||
23 | #include <linux/platform_device.h> | ||
24 | #include <linux/phy/phy.h> | ||
25 | |||
26 | struct qcom_ipq806x_sata_phy { | ||
27 | void __iomem *mmio; | ||
28 | struct clk *cfg_clk; | ||
29 | struct device *dev; | ||
30 | }; | ||
31 | |||
32 | #define __set(v, a, b) (((v) << (b)) & GENMASK(a, b)) | ||
33 | |||
34 | #define SATA_PHY_P0_PARAM0 0x200 | ||
35 | #define SATA_PHY_P0_PARAM0_P0_TX_PREEMPH_GEN3(x) __set(x, 17, 12) | ||
36 | #define SATA_PHY_P0_PARAM0_P0_TX_PREEMPH_GEN3_MASK GENMASK(17, 12) | ||
37 | #define SATA_PHY_P0_PARAM0_P0_TX_PREEMPH_GEN2(x) __set(x, 11, 6) | ||
38 | #define SATA_PHY_P0_PARAM0_P0_TX_PREEMPH_GEN2_MASK GENMASK(11, 6) | ||
39 | #define SATA_PHY_P0_PARAM0_P0_TX_PREEMPH_GEN1(x) __set(x, 5, 0) | ||
40 | #define SATA_PHY_P0_PARAM0_P0_TX_PREEMPH_GEN1_MASK GENMASK(5, 0) | ||
41 | |||
42 | #define SATA_PHY_P0_PARAM1 0x204 | ||
43 | #define SATA_PHY_P0_PARAM1_RESERVED_BITS31_21(x) __set(x, 31, 21) | ||
44 | #define SATA_PHY_P0_PARAM1_P0_TX_AMPLITUDE_GEN3(x) __set(x, 20, 14) | ||
45 | #define SATA_PHY_P0_PARAM1_P0_TX_AMPLITUDE_GEN3_MASK GENMASK(20, 14) | ||
46 | #define SATA_PHY_P0_PARAM1_P0_TX_AMPLITUDE_GEN2(x) __set(x, 13, 7) | ||
47 | #define SATA_PHY_P0_PARAM1_P0_TX_AMPLITUDE_GEN2_MASK GENMASK(13, 7) | ||
48 | #define SATA_PHY_P0_PARAM1_P0_TX_AMPLITUDE_GEN1(x) __set(x, 6, 0) | ||
49 | #define SATA_PHY_P0_PARAM1_P0_TX_AMPLITUDE_GEN1_MASK GENMASK(6, 0) | ||
50 | |||
51 | #define SATA_PHY_P0_PARAM2 0x208 | ||
52 | #define SATA_PHY_P0_PARAM2_RX_EQ(x) __set(x, 20, 18) | ||
53 | #define SATA_PHY_P0_PARAM2_RX_EQ_MASK GENMASK(20, 18) | ||
54 | |||
55 | #define SATA_PHY_P0_PARAM3 0x20C | ||
56 | #define SATA_PHY_SSC_EN 0x8 | ||
57 | #define SATA_PHY_P0_PARAM4 0x210 | ||
58 | #define SATA_PHY_REF_SSP_EN 0x2 | ||
59 | #define SATA_PHY_RESET 0x1 | ||
60 | |||
61 | static int qcom_ipq806x_sata_phy_init(struct phy *generic_phy) | ||
62 | { | ||
63 | struct qcom_ipq806x_sata_phy *phy = phy_get_drvdata(generic_phy); | ||
64 | u32 reg; | ||
65 | |||
66 | /* Setting SSC_EN to 1 */ | ||
67 | reg = readl_relaxed(phy->mmio + SATA_PHY_P0_PARAM3); | ||
68 | reg = reg | SATA_PHY_SSC_EN; | ||
69 | writel_relaxed(reg, phy->mmio + SATA_PHY_P0_PARAM3); | ||
70 | |||
71 | reg = readl_relaxed(phy->mmio + SATA_PHY_P0_PARAM0) & | ||
72 | ~(SATA_PHY_P0_PARAM0_P0_TX_PREEMPH_GEN3_MASK | | ||
73 | SATA_PHY_P0_PARAM0_P0_TX_PREEMPH_GEN2_MASK | | ||
74 | SATA_PHY_P0_PARAM0_P0_TX_PREEMPH_GEN1_MASK); | ||
75 | reg |= SATA_PHY_P0_PARAM0_P0_TX_PREEMPH_GEN3(0xf); | ||
76 | writel_relaxed(reg, phy->mmio + SATA_PHY_P0_PARAM0); | ||
77 | |||
78 | reg = readl_relaxed(phy->mmio + SATA_PHY_P0_PARAM1) & | ||
79 | ~(SATA_PHY_P0_PARAM1_P0_TX_AMPLITUDE_GEN3_MASK | | ||
80 | SATA_PHY_P0_PARAM1_P0_TX_AMPLITUDE_GEN2_MASK | | ||
81 | SATA_PHY_P0_PARAM1_P0_TX_AMPLITUDE_GEN1_MASK); | ||
82 | reg |= SATA_PHY_P0_PARAM1_P0_TX_AMPLITUDE_GEN3(0x55) | | ||
83 | SATA_PHY_P0_PARAM1_P0_TX_AMPLITUDE_GEN2(0x55) | | ||
84 | SATA_PHY_P0_PARAM1_P0_TX_AMPLITUDE_GEN1(0x55); | ||
85 | writel_relaxed(reg, phy->mmio + SATA_PHY_P0_PARAM1); | ||
86 | |||
87 | reg = readl_relaxed(phy->mmio + SATA_PHY_P0_PARAM2) & | ||
88 | ~SATA_PHY_P0_PARAM2_RX_EQ_MASK; | ||
89 | reg |= SATA_PHY_P0_PARAM2_RX_EQ(0x3); | ||
90 | writel_relaxed(reg, phy->mmio + SATA_PHY_P0_PARAM2); | ||
91 | |||
92 | /* Setting PHY_RESET to 1 */ | ||
93 | reg = readl_relaxed(phy->mmio + SATA_PHY_P0_PARAM4); | ||
94 | reg = reg | SATA_PHY_RESET; | ||
95 | writel_relaxed(reg, phy->mmio + SATA_PHY_P0_PARAM4); | ||
96 | |||
97 | /* Setting REF_SSP_EN to 1 */ | ||
98 | reg = readl_relaxed(phy->mmio + SATA_PHY_P0_PARAM4); | ||
99 | reg = reg | SATA_PHY_REF_SSP_EN | SATA_PHY_RESET; | ||
100 | writel_relaxed(reg, phy->mmio + SATA_PHY_P0_PARAM4); | ||
101 | |||
102 | /* make sure all changes complete before we let the PHY out of reset */ | ||
103 | mb(); | ||
104 | |||
105 | /* sleep for max. 50us more to combine processor wakeups */ | ||
106 | usleep_range(20, 20 + 50); | ||
107 | |||
108 | /* Clearing PHY_RESET to 0 */ | ||
109 | reg = readl_relaxed(phy->mmio + SATA_PHY_P0_PARAM4); | ||
110 | reg = reg & ~SATA_PHY_RESET; | ||
111 | writel_relaxed(reg, phy->mmio + SATA_PHY_P0_PARAM4); | ||
112 | |||
113 | return 0; | ||
114 | } | ||
115 | |||
116 | static int qcom_ipq806x_sata_phy_exit(struct phy *generic_phy) | ||
117 | { | ||
118 | struct qcom_ipq806x_sata_phy *phy = phy_get_drvdata(generic_phy); | ||
119 | u32 reg; | ||
120 | |||
121 | /* Setting PHY_RESET to 1 */ | ||
122 | reg = readl_relaxed(phy->mmio + SATA_PHY_P0_PARAM4); | ||
123 | reg = reg | SATA_PHY_RESET; | ||
124 | writel_relaxed(reg, phy->mmio + SATA_PHY_P0_PARAM4); | ||
125 | |||
126 | return 0; | ||
127 | } | ||
128 | |||
129 | static struct phy_ops qcom_ipq806x_sata_phy_ops = { | ||
130 | .init = qcom_ipq806x_sata_phy_init, | ||
131 | .exit = qcom_ipq806x_sata_phy_exit, | ||
132 | .owner = THIS_MODULE, | ||
133 | }; | ||
134 | |||
135 | static int qcom_ipq806x_sata_phy_probe(struct platform_device *pdev) | ||
136 | { | ||
137 | struct qcom_ipq806x_sata_phy *phy; | ||
138 | struct device *dev = &pdev->dev; | ||
139 | struct resource *res; | ||
140 | struct phy_provider *phy_provider; | ||
141 | struct phy *generic_phy; | ||
142 | int ret; | ||
143 | |||
144 | phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL); | ||
145 | if (!phy) | ||
146 | return -ENOMEM; | ||
147 | |||
148 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
149 | phy->mmio = devm_ioremap_resource(dev, res); | ||
150 | if (IS_ERR(phy->mmio)) | ||
151 | return PTR_ERR(phy->mmio); | ||
152 | |||
153 | generic_phy = devm_phy_create(dev, NULL, &qcom_ipq806x_sata_phy_ops, | ||
154 | NULL); | ||
155 | if (IS_ERR(generic_phy)) { | ||
156 | dev_err(dev, "%s: failed to create phy\n", __func__); | ||
157 | return PTR_ERR(generic_phy); | ||
158 | } | ||
159 | |||
160 | phy->dev = dev; | ||
161 | phy_set_drvdata(generic_phy, phy); | ||
162 | platform_set_drvdata(pdev, phy); | ||
163 | |||
164 | phy->cfg_clk = devm_clk_get(dev, "cfg"); | ||
165 | if (IS_ERR(phy->cfg_clk)) { | ||
166 | dev_err(dev, "Failed to get sata cfg clock\n"); | ||
167 | return PTR_ERR(phy->cfg_clk); | ||
168 | } | ||
169 | |||
170 | ret = clk_prepare_enable(phy->cfg_clk); | ||
171 | if (ret) | ||
172 | return ret; | ||
173 | |||
174 | phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); | ||
175 | if (IS_ERR(phy_provider)) { | ||
176 | clk_disable_unprepare(phy->cfg_clk); | ||
177 | dev_err(dev, "%s: failed to register phy\n", __func__); | ||
178 | return PTR_ERR(phy_provider); | ||
179 | } | ||
180 | |||
181 | return 0; | ||
182 | } | ||
183 | |||
184 | static int qcom_ipq806x_sata_phy_remove(struct platform_device *pdev) | ||
185 | { | ||
186 | struct qcom_ipq806x_sata_phy *phy = platform_get_drvdata(pdev); | ||
187 | |||
188 | clk_disable_unprepare(phy->cfg_clk); | ||
189 | |||
190 | return 0; | ||
191 | } | ||
192 | |||
193 | static const struct of_device_id qcom_ipq806x_sata_phy_of_match[] = { | ||
194 | { .compatible = "qcom,ipq806x-sata-phy" }, | ||
195 | { }, | ||
196 | }; | ||
197 | MODULE_DEVICE_TABLE(of, qcom_ipq806x_sata_phy_of_match); | ||
198 | |||
199 | static struct platform_driver qcom_ipq806x_sata_phy_driver = { | ||
200 | .probe = qcom_ipq806x_sata_phy_probe, | ||
201 | .remove = qcom_ipq806x_sata_phy_remove, | ||
202 | .driver = { | ||
203 | .name = "qcom-ipq806x-sata-phy", | ||
204 | .owner = THIS_MODULE, | ||
205 | .of_match_table = qcom_ipq806x_sata_phy_of_match, | ||
206 | } | ||
207 | }; | ||
208 | module_platform_driver(qcom_ipq806x_sata_phy_driver); | ||
209 | |||
210 | MODULE_DESCRIPTION("QCOM IPQ806x SATA PHY driver"); | ||
211 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/phy/phy-s5pv210-usb2.c b/drivers/phy/phy-s5pv210-usb2.c new file mode 100644 index 000000000000..004d320767e4 --- /dev/null +++ b/drivers/phy/phy-s5pv210-usb2.c | |||
@@ -0,0 +1,187 @@ | |||
1 | /* | ||
2 | * Samsung SoC USB 1.1/2.0 PHY driver - S5PV210 support | ||
3 | * | ||
4 | * Copyright (C) 2013 Samsung Electronics Co., Ltd. | ||
5 | * Authors: Kamil Debski <k.debski@samsung.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #include <linux/delay.h> | ||
13 | #include <linux/io.h> | ||
14 | #include <linux/phy/phy.h> | ||
15 | #include "phy-samsung-usb2.h" | ||
16 | |||
17 | /* Exynos USB PHY registers */ | ||
18 | |||
19 | /* PHY power control */ | ||
20 | #define S5PV210_UPHYPWR 0x0 | ||
21 | |||
22 | #define S5PV210_UPHYPWR_PHY0_SUSPEND BIT(0) | ||
23 | #define S5PV210_UPHYPWR_PHY0_PWR BIT(3) | ||
24 | #define S5PV210_UPHYPWR_PHY0_OTG_PWR BIT(4) | ||
25 | #define S5PV210_UPHYPWR_PHY0 ( \ | ||
26 | S5PV210_UPHYPWR_PHY0_SUSPEND | \ | ||
27 | S5PV210_UPHYPWR_PHY0_PWR | \ | ||
28 | S5PV210_UPHYPWR_PHY0_OTG_PWR) | ||
29 | |||
30 | #define S5PV210_UPHYPWR_PHY1_SUSPEND BIT(6) | ||
31 | #define S5PV210_UPHYPWR_PHY1_PWR BIT(7) | ||
32 | #define S5PV210_UPHYPWR_PHY1 ( \ | ||
33 | S5PV210_UPHYPWR_PHY1_SUSPEND | \ | ||
34 | S5PV210_UPHYPWR_PHY1_PWR) | ||
35 | |||
36 | /* PHY clock control */ | ||
37 | #define S5PV210_UPHYCLK 0x4 | ||
38 | |||
39 | #define S5PV210_UPHYCLK_PHYFSEL_MASK (0x3 << 0) | ||
40 | #define S5PV210_UPHYCLK_PHYFSEL_48MHZ (0x0 << 0) | ||
41 | #define S5PV210_UPHYCLK_PHYFSEL_24MHZ (0x3 << 0) | ||
42 | #define S5PV210_UPHYCLK_PHYFSEL_12MHZ (0x2 << 0) | ||
43 | |||
44 | #define S5PV210_UPHYCLK_PHY0_ID_PULLUP BIT(2) | ||
45 | #define S5PV210_UPHYCLK_PHY0_COMMON_ON BIT(4) | ||
46 | #define S5PV210_UPHYCLK_PHY1_COMMON_ON BIT(7) | ||
47 | |||
48 | /* PHY reset control */ | ||
49 | #define S5PV210_UPHYRST 0x8 | ||
50 | |||
51 | #define S5PV210_URSTCON_PHY0 BIT(0) | ||
52 | #define S5PV210_URSTCON_OTG_HLINK BIT(1) | ||
53 | #define S5PV210_URSTCON_OTG_PHYLINK BIT(2) | ||
54 | #define S5PV210_URSTCON_PHY1_ALL BIT(3) | ||
55 | #define S5PV210_URSTCON_HOST_LINK_ALL BIT(4) | ||
56 | |||
57 | /* Isolation, configured in the power management unit */ | ||
58 | #define S5PV210_USB_ISOL_OFFSET 0x680c | ||
59 | #define S5PV210_USB_ISOL_DEVICE BIT(0) | ||
60 | #define S5PV210_USB_ISOL_HOST BIT(1) | ||
61 | |||
62 | |||
63 | enum s5pv210_phy_id { | ||
64 | S5PV210_DEVICE, | ||
65 | S5PV210_HOST, | ||
66 | S5PV210_NUM_PHYS, | ||
67 | }; | ||
68 | |||
69 | /* | ||
70 | * s5pv210_rate_to_clk() converts the supplied clock rate to the value that | ||
71 | * can be written to the phy register. | ||
72 | */ | ||
73 | static int s5pv210_rate_to_clk(unsigned long rate, u32 *reg) | ||
74 | { | ||
75 | switch (rate) { | ||
76 | case 12 * MHZ: | ||
77 | *reg = S5PV210_UPHYCLK_PHYFSEL_12MHZ; | ||
78 | break; | ||
79 | case 24 * MHZ: | ||
80 | *reg = S5PV210_UPHYCLK_PHYFSEL_24MHZ; | ||
81 | break; | ||
82 | case 48 * MHZ: | ||
83 | *reg = S5PV210_UPHYCLK_PHYFSEL_48MHZ; | ||
84 | break; | ||
85 | default: | ||
86 | return -EINVAL; | ||
87 | } | ||
88 | |||
89 | return 0; | ||
90 | } | ||
91 | |||
92 | static void s5pv210_isol(struct samsung_usb2_phy_instance *inst, bool on) | ||
93 | { | ||
94 | struct samsung_usb2_phy_driver *drv = inst->drv; | ||
95 | u32 mask; | ||
96 | |||
97 | switch (inst->cfg->id) { | ||
98 | case S5PV210_DEVICE: | ||
99 | mask = S5PV210_USB_ISOL_DEVICE; | ||
100 | break; | ||
101 | case S5PV210_HOST: | ||
102 | mask = S5PV210_USB_ISOL_HOST; | ||
103 | break; | ||
104 | default: | ||
105 | return; | ||
106 | }; | ||
107 | |||
108 | regmap_update_bits(drv->reg_pmu, S5PV210_USB_ISOL_OFFSET, | ||
109 | mask, on ? 0 : mask); | ||
110 | } | ||
111 | |||
112 | static void s5pv210_phy_pwr(struct samsung_usb2_phy_instance *inst, bool on) | ||
113 | { | ||
114 | struct samsung_usb2_phy_driver *drv = inst->drv; | ||
115 | u32 rstbits = 0; | ||
116 | u32 phypwr = 0; | ||
117 | u32 rst; | ||
118 | u32 pwr; | ||
119 | |||
120 | switch (inst->cfg->id) { | ||
121 | case S5PV210_DEVICE: | ||
122 | phypwr = S5PV210_UPHYPWR_PHY0; | ||
123 | rstbits = S5PV210_URSTCON_PHY0; | ||
124 | break; | ||
125 | case S5PV210_HOST: | ||
126 | phypwr = S5PV210_UPHYPWR_PHY1; | ||
127 | rstbits = S5PV210_URSTCON_PHY1_ALL | | ||
128 | S5PV210_URSTCON_HOST_LINK_ALL; | ||
129 | break; | ||
130 | }; | ||
131 | |||
132 | if (on) { | ||
133 | writel(drv->ref_reg_val, drv->reg_phy + S5PV210_UPHYCLK); | ||
134 | |||
135 | pwr = readl(drv->reg_phy + S5PV210_UPHYPWR); | ||
136 | pwr &= ~phypwr; | ||
137 | writel(pwr, drv->reg_phy + S5PV210_UPHYPWR); | ||
138 | |||
139 | rst = readl(drv->reg_phy + S5PV210_UPHYRST); | ||
140 | rst |= rstbits; | ||
141 | writel(rst, drv->reg_phy + S5PV210_UPHYRST); | ||
142 | udelay(10); | ||
143 | rst &= ~rstbits; | ||
144 | writel(rst, drv->reg_phy + S5PV210_UPHYRST); | ||
145 | } else { | ||
146 | pwr = readl(drv->reg_phy + S5PV210_UPHYPWR); | ||
147 | pwr |= phypwr; | ||
148 | writel(pwr, drv->reg_phy + S5PV210_UPHYPWR); | ||
149 | } | ||
150 | } | ||
151 | |||
152 | static int s5pv210_power_on(struct samsung_usb2_phy_instance *inst) | ||
153 | { | ||
154 | s5pv210_isol(inst, 0); | ||
155 | s5pv210_phy_pwr(inst, 1); | ||
156 | |||
157 | return 0; | ||
158 | } | ||
159 | |||
160 | static int s5pv210_power_off(struct samsung_usb2_phy_instance *inst) | ||
161 | { | ||
162 | s5pv210_phy_pwr(inst, 0); | ||
163 | s5pv210_isol(inst, 1); | ||
164 | |||
165 | return 0; | ||
166 | } | ||
167 | |||
168 | static const struct samsung_usb2_common_phy s5pv210_phys[S5PV210_NUM_PHYS] = { | ||
169 | [S5PV210_DEVICE] = { | ||
170 | .label = "device", | ||
171 | .id = S5PV210_DEVICE, | ||
172 | .power_on = s5pv210_power_on, | ||
173 | .power_off = s5pv210_power_off, | ||
174 | }, | ||
175 | [S5PV210_HOST] = { | ||
176 | .label = "host", | ||
177 | .id = S5PV210_HOST, | ||
178 | .power_on = s5pv210_power_on, | ||
179 | .power_off = s5pv210_power_off, | ||
180 | }, | ||
181 | }; | ||
182 | |||
183 | const struct samsung_usb2_phy_config s5pv210_usb2_phy_config = { | ||
184 | .num_phys = ARRAY_SIZE(s5pv210_phys), | ||
185 | .phys = s5pv210_phys, | ||
186 | .rate_to_clk = s5pv210_rate_to_clk, | ||
187 | }; | ||
diff --git a/drivers/phy/phy-samsung-usb2.c b/drivers/phy/phy-samsung-usb2.c index 8a8c6bc8709a..3732ca25e09f 100644 --- a/drivers/phy/phy-samsung-usb2.c +++ b/drivers/phy/phy-samsung-usb2.c | |||
@@ -87,6 +87,12 @@ static struct phy *samsung_usb2_phy_xlate(struct device *dev, | |||
87 | } | 87 | } |
88 | 88 | ||
89 | static const struct of_device_id samsung_usb2_phy_of_match[] = { | 89 | static const struct of_device_id samsung_usb2_phy_of_match[] = { |
90 | #ifdef CONFIG_PHY_EXYNOS4X12_USB2 | ||
91 | { | ||
92 | .compatible = "samsung,exynos3250-usb2-phy", | ||
93 | .data = &exynos3250_usb2_phy_config, | ||
94 | }, | ||
95 | #endif | ||
90 | #ifdef CONFIG_PHY_EXYNOS4210_USB2 | 96 | #ifdef CONFIG_PHY_EXYNOS4210_USB2 |
91 | { | 97 | { |
92 | .compatible = "samsung,exynos4210-usb2-phy", | 98 | .compatible = "samsung,exynos4210-usb2-phy", |
@@ -105,8 +111,15 @@ static const struct of_device_id samsung_usb2_phy_of_match[] = { | |||
105 | .data = &exynos5250_usb2_phy_config, | 111 | .data = &exynos5250_usb2_phy_config, |
106 | }, | 112 | }, |
107 | #endif | 113 | #endif |
114 | #ifdef CONFIG_PHY_S5PV210_USB2 | ||
115 | { | ||
116 | .compatible = "samsung,s5pv210-usb2-phy", | ||
117 | .data = &s5pv210_usb2_phy_config, | ||
118 | }, | ||
119 | #endif | ||
108 | { }, | 120 | { }, |
109 | }; | 121 | }; |
122 | MODULE_DEVICE_TABLE(of, samsung_usb2_phy_of_match); | ||
110 | 123 | ||
111 | static int samsung_usb2_phy_probe(struct platform_device *pdev) | 124 | static int samsung_usb2_phy_probe(struct platform_device *pdev) |
112 | { | 125 | { |
@@ -189,7 +202,8 @@ static int samsung_usb2_phy_probe(struct platform_device *pdev) | |||
189 | struct samsung_usb2_phy_instance *p = &drv->instances[i]; | 202 | struct samsung_usb2_phy_instance *p = &drv->instances[i]; |
190 | 203 | ||
191 | dev_dbg(dev, "Creating phy \"%s\"\n", label); | 204 | dev_dbg(dev, "Creating phy \"%s\"\n", label); |
192 | p->phy = devm_phy_create(dev, &samsung_usb2_phy_ops, NULL); | 205 | p->phy = devm_phy_create(dev, NULL, &samsung_usb2_phy_ops, |
206 | NULL); | ||
193 | if (IS_ERR(p->phy)) { | 207 | if (IS_ERR(p->phy)) { |
194 | dev_err(drv->dev, "Failed to create usb2_phy \"%s\"\n", | 208 | dev_err(drv->dev, "Failed to create usb2_phy \"%s\"\n", |
195 | label); | 209 | label); |
diff --git a/drivers/phy/phy-samsung-usb2.h b/drivers/phy/phy-samsung-usb2.h index 45b3170652bd..44bead9b8f34 100644 --- a/drivers/phy/phy-samsung-usb2.h +++ b/drivers/phy/phy-samsung-usb2.h | |||
@@ -29,7 +29,8 @@ struct samsung_usb2_phy_instance { | |||
29 | const struct samsung_usb2_common_phy *cfg; | 29 | const struct samsung_usb2_common_phy *cfg; |
30 | struct phy *phy; | 30 | struct phy *phy; |
31 | struct samsung_usb2_phy_driver *drv; | 31 | struct samsung_usb2_phy_driver *drv; |
32 | bool enabled; | 32 | int int_cnt; |
33 | int ext_cnt; | ||
33 | }; | 34 | }; |
34 | 35 | ||
35 | struct samsung_usb2_phy_driver { | 36 | struct samsung_usb2_phy_driver { |
@@ -59,9 +60,12 @@ struct samsung_usb2_phy_config { | |||
59 | int (*rate_to_clk)(unsigned long, u32 *); | 60 | int (*rate_to_clk)(unsigned long, u32 *); |
60 | unsigned int num_phys; | 61 | unsigned int num_phys; |
61 | bool has_mode_switch; | 62 | bool has_mode_switch; |
63 | bool has_refclk_sel; | ||
62 | }; | 64 | }; |
63 | 65 | ||
66 | extern const struct samsung_usb2_phy_config exynos3250_usb2_phy_config; | ||
64 | extern const struct samsung_usb2_phy_config exynos4210_usb2_phy_config; | 67 | extern const struct samsung_usb2_phy_config exynos4210_usb2_phy_config; |
65 | extern const struct samsung_usb2_phy_config exynos4x12_usb2_phy_config; | 68 | extern const struct samsung_usb2_phy_config exynos4x12_usb2_phy_config; |
66 | extern const struct samsung_usb2_phy_config exynos5250_usb2_phy_config; | 69 | extern const struct samsung_usb2_phy_config exynos5250_usb2_phy_config; |
70 | extern const struct samsung_usb2_phy_config s5pv210_usb2_phy_config; | ||
67 | #endif | 71 | #endif |
diff --git a/drivers/phy/phy-spear1310-miphy.c b/drivers/phy/phy-spear1310-miphy.c index c58c869d57e0..6dcbfcddb372 100644 --- a/drivers/phy/phy-spear1310-miphy.c +++ b/drivers/phy/phy-spear1310-miphy.c | |||
@@ -229,7 +229,7 @@ static int spear1310_miphy_probe(struct platform_device *pdev) | |||
229 | return -EINVAL; | 229 | return -EINVAL; |
230 | } | 230 | } |
231 | 231 | ||
232 | priv->phy = devm_phy_create(dev, &spear1310_miphy_ops, NULL); | 232 | priv->phy = devm_phy_create(dev, NULL, &spear1310_miphy_ops, NULL); |
233 | if (IS_ERR(priv->phy)) { | 233 | if (IS_ERR(priv->phy)) { |
234 | dev_err(dev, "failed to create SATA PCIe PHY\n"); | 234 | dev_err(dev, "failed to create SATA PCIe PHY\n"); |
235 | return PTR_ERR(priv->phy); | 235 | return PTR_ERR(priv->phy); |
diff --git a/drivers/phy/phy-spear1340-miphy.c b/drivers/phy/phy-spear1340-miphy.c index 8de98adf21c3..7135ba2603b6 100644 --- a/drivers/phy/phy-spear1340-miphy.c +++ b/drivers/phy/phy-spear1340-miphy.c | |||
@@ -261,7 +261,7 @@ static int spear1340_miphy_probe(struct platform_device *pdev) | |||
261 | return PTR_ERR(priv->misc); | 261 | return PTR_ERR(priv->misc); |
262 | } | 262 | } |
263 | 263 | ||
264 | priv->phy = devm_phy_create(dev, &spear1340_miphy_ops, NULL); | 264 | priv->phy = devm_phy_create(dev, NULL, &spear1340_miphy_ops, NULL); |
265 | if (IS_ERR(priv->phy)) { | 265 | if (IS_ERR(priv->phy)) { |
266 | dev_err(dev, "failed to create SATA PCIe PHY\n"); | 266 | dev_err(dev, "failed to create SATA PCIe PHY\n"); |
267 | return PTR_ERR(priv->phy); | 267 | return PTR_ERR(priv->phy); |
diff --git a/drivers/phy/phy-sun4i-usb.c b/drivers/phy/phy-sun4i-usb.c index 115d8d5190d5..61ebea49709b 100644 --- a/drivers/phy/phy-sun4i-usb.c +++ b/drivers/phy/phy-sun4i-usb.c | |||
@@ -22,6 +22,7 @@ | |||
22 | */ | 22 | */ |
23 | 23 | ||
24 | #include <linux/clk.h> | 24 | #include <linux/clk.h> |
25 | #include <linux/err.h> | ||
25 | #include <linux/io.h> | 26 | #include <linux/io.h> |
26 | #include <linux/kernel.h> | 27 | #include <linux/kernel.h> |
27 | #include <linux/module.h> | 28 | #include <linux/module.h> |
@@ -294,7 +295,7 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev) | |||
294 | return PTR_ERR(phy->pmu); | 295 | return PTR_ERR(phy->pmu); |
295 | } | 296 | } |
296 | 297 | ||
297 | phy->phy = devm_phy_create(dev, &sun4i_usb_phy_ops, NULL); | 298 | phy->phy = devm_phy_create(dev, NULL, &sun4i_usb_phy_ops, NULL); |
298 | if (IS_ERR(phy->phy)) { | 299 | if (IS_ERR(phy->phy)) { |
299 | dev_err(dev, "failed to create PHY %d\n", i); | 300 | dev_err(dev, "failed to create PHY %d\n", i); |
300 | return PTR_ERR(phy->phy); | 301 | return PTR_ERR(phy->phy); |
@@ -306,10 +307,8 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev) | |||
306 | 307 | ||
307 | dev_set_drvdata(dev, data); | 308 | dev_set_drvdata(dev, data); |
308 | phy_provider = devm_of_phy_provider_register(dev, sun4i_usb_phy_xlate); | 309 | phy_provider = devm_of_phy_provider_register(dev, sun4i_usb_phy_xlate); |
309 | if (IS_ERR(phy_provider)) | ||
310 | return PTR_ERR(phy_provider); | ||
311 | 310 | ||
312 | return 0; | 311 | return PTR_ERR_OR_ZERO(phy_provider); |
313 | } | 312 | } |
314 | 313 | ||
315 | static const struct of_device_id sun4i_usb_phy_of_match[] = { | 314 | static const struct of_device_id sun4i_usb_phy_of_match[] = { |
diff --git a/drivers/phy/phy-ti-pipe3.c b/drivers/phy/phy-ti-pipe3.c index 591367654613..b964aa967b46 100644 --- a/drivers/phy/phy-ti-pipe3.c +++ b/drivers/phy/phy-ti-pipe3.c | |||
@@ -80,7 +80,9 @@ struct ti_pipe3 { | |||
80 | struct clk *wkupclk; | 80 | struct clk *wkupclk; |
81 | struct clk *sys_clk; | 81 | struct clk *sys_clk; |
82 | struct clk *refclk; | 82 | struct clk *refclk; |
83 | struct clk *div_clk; | ||
83 | struct pipe3_dpll_map *dpll_map; | 84 | struct pipe3_dpll_map *dpll_map; |
85 | u8 id; | ||
84 | }; | 86 | }; |
85 | 87 | ||
86 | static struct pipe3_dpll_map dpll_map_usb[] = { | 88 | static struct pipe3_dpll_map dpll_map_usb[] = { |
@@ -215,6 +217,11 @@ static int ti_pipe3_init(struct phy *x) | |||
215 | u32 val; | 217 | u32 val; |
216 | int ret = 0; | 218 | int ret = 0; |
217 | 219 | ||
220 | if (of_device_is_compatible(phy->dev->of_node, "ti,phy-pipe3-pcie")) { | ||
221 | omap_control_pcie_pcs(phy->control_dev, phy->id, 0xF1); | ||
222 | return 0; | ||
223 | } | ||
224 | |||
218 | /* Bring it out of IDLE if it is IDLE */ | 225 | /* Bring it out of IDLE if it is IDLE */ |
219 | val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION2); | 226 | val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION2); |
220 | if (val & PLL_IDLE) { | 227 | if (val & PLL_IDLE) { |
@@ -238,8 +245,11 @@ static int ti_pipe3_exit(struct phy *x) | |||
238 | u32 val; | 245 | u32 val; |
239 | unsigned long timeout; | 246 | unsigned long timeout; |
240 | 247 | ||
241 | /* SATA DPLL can't be powered down due to Errata i783 */ | 248 | /* SATA DPLL can't be powered down due to Errata i783 and PCIe |
242 | if (of_device_is_compatible(phy->dev->of_node, "ti,phy-pipe3-sata")) | 249 | * does not have internal DPLL |
250 | */ | ||
251 | if (of_device_is_compatible(phy->dev->of_node, "ti,phy-pipe3-sata") || | ||
252 | of_device_is_compatible(phy->dev->of_node, "ti,phy-pipe3-pcie")) | ||
243 | return 0; | 253 | return 0; |
244 | 254 | ||
245 | /* Put DPLL in IDLE mode */ | 255 | /* Put DPLL in IDLE mode */ |
@@ -286,32 +296,41 @@ static int ti_pipe3_probe(struct platform_device *pdev) | |||
286 | struct device_node *control_node; | 296 | struct device_node *control_node; |
287 | struct platform_device *control_pdev; | 297 | struct platform_device *control_pdev; |
288 | const struct of_device_id *match; | 298 | const struct of_device_id *match; |
289 | 299 | struct clk *clk; | |
290 | match = of_match_device(of_match_ptr(ti_pipe3_id_table), &pdev->dev); | ||
291 | if (!match) | ||
292 | return -EINVAL; | ||
293 | 300 | ||
294 | phy = devm_kzalloc(&pdev->dev, sizeof(*phy), GFP_KERNEL); | 301 | phy = devm_kzalloc(&pdev->dev, sizeof(*phy), GFP_KERNEL); |
295 | if (!phy) { | 302 | if (!phy) { |
296 | dev_err(&pdev->dev, "unable to alloc mem for TI PIPE3 PHY\n"); | 303 | dev_err(&pdev->dev, "unable to alloc mem for TI PIPE3 PHY\n"); |
297 | return -ENOMEM; | 304 | return -ENOMEM; |
298 | } | 305 | } |
306 | phy->dev = &pdev->dev; | ||
299 | 307 | ||
300 | phy->dpll_map = (struct pipe3_dpll_map *)match->data; | 308 | if (!of_device_is_compatible(node, "ti,phy-pipe3-pcie")) { |
301 | if (!phy->dpll_map) { | 309 | match = of_match_device(of_match_ptr(ti_pipe3_id_table), |
302 | dev_err(&pdev->dev, "no DPLL data\n"); | 310 | &pdev->dev); |
303 | return -EINVAL; | 311 | if (!match) |
304 | } | 312 | return -EINVAL; |
305 | 313 | ||
306 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pll_ctrl"); | 314 | phy->dpll_map = (struct pipe3_dpll_map *)match->data; |
307 | phy->pll_ctrl_base = devm_ioremap_resource(&pdev->dev, res); | 315 | if (!phy->dpll_map) { |
308 | if (IS_ERR(phy->pll_ctrl_base)) | 316 | dev_err(&pdev->dev, "no DPLL data\n"); |
309 | return PTR_ERR(phy->pll_ctrl_base); | 317 | return -EINVAL; |
318 | } | ||
310 | 319 | ||
311 | phy->dev = &pdev->dev; | 320 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, |
321 | "pll_ctrl"); | ||
322 | phy->pll_ctrl_base = devm_ioremap_resource(&pdev->dev, res); | ||
323 | if (IS_ERR(phy->pll_ctrl_base)) | ||
324 | return PTR_ERR(phy->pll_ctrl_base); | ||
312 | 325 | ||
313 | if (!of_device_is_compatible(node, "ti,phy-pipe3-sata")) { | 326 | phy->sys_clk = devm_clk_get(phy->dev, "sysclk"); |
327 | if (IS_ERR(phy->sys_clk)) { | ||
328 | dev_err(&pdev->dev, "unable to get sysclk\n"); | ||
329 | return -EINVAL; | ||
330 | } | ||
331 | } | ||
314 | 332 | ||
333 | if (!of_device_is_compatible(node, "ti,phy-pipe3-sata")) { | ||
315 | phy->wkupclk = devm_clk_get(phy->dev, "wkupclk"); | 334 | phy->wkupclk = devm_clk_get(phy->dev, "wkupclk"); |
316 | if (IS_ERR(phy->wkupclk)) { | 335 | if (IS_ERR(phy->wkupclk)) { |
317 | dev_err(&pdev->dev, "unable to get wkupclk\n"); | 336 | dev_err(&pdev->dev, "unable to get wkupclk\n"); |
@@ -328,10 +347,38 @@ static int ti_pipe3_probe(struct platform_device *pdev) | |||
328 | phy->refclk = ERR_PTR(-ENODEV); | 347 | phy->refclk = ERR_PTR(-ENODEV); |
329 | } | 348 | } |
330 | 349 | ||
331 | phy->sys_clk = devm_clk_get(phy->dev, "sysclk"); | 350 | if (of_device_is_compatible(node, "ti,phy-pipe3-pcie")) { |
332 | if (IS_ERR(phy->sys_clk)) { | 351 | if (of_property_read_u8(node, "id", &phy->id) < 0) |
333 | dev_err(&pdev->dev, "unable to get sysclk\n"); | 352 | phy->id = 1; |
334 | return -EINVAL; | 353 | |
354 | clk = devm_clk_get(phy->dev, "dpll_ref"); | ||
355 | if (IS_ERR(clk)) { | ||
356 | dev_err(&pdev->dev, "unable to get dpll ref clk\n"); | ||
357 | return PTR_ERR(clk); | ||
358 | } | ||
359 | clk_set_rate(clk, 1500000000); | ||
360 | |||
361 | clk = devm_clk_get(phy->dev, "dpll_ref_m2"); | ||
362 | if (IS_ERR(clk)) { | ||
363 | dev_err(&pdev->dev, "unable to get dpll ref m2 clk\n"); | ||
364 | return PTR_ERR(clk); | ||
365 | } | ||
366 | clk_set_rate(clk, 100000000); | ||
367 | |||
368 | clk = devm_clk_get(phy->dev, "phy-div"); | ||
369 | if (IS_ERR(clk)) { | ||
370 | dev_err(&pdev->dev, "unable to get phy-div clk\n"); | ||
371 | return PTR_ERR(clk); | ||
372 | } | ||
373 | clk_set_rate(clk, 100000000); | ||
374 | |||
375 | phy->div_clk = devm_clk_get(phy->dev, "div-clk"); | ||
376 | if (IS_ERR(phy->div_clk)) { | ||
377 | dev_err(&pdev->dev, "unable to get div-clk\n"); | ||
378 | return PTR_ERR(phy->div_clk); | ||
379 | } | ||
380 | } else { | ||
381 | phy->div_clk = ERR_PTR(-ENODEV); | ||
335 | } | 382 | } |
336 | 383 | ||
337 | control_node = of_parse_phandle(node, "ctrl-module", 0); | 384 | control_node = of_parse_phandle(node, "ctrl-module", 0); |
@@ -353,7 +400,7 @@ static int ti_pipe3_probe(struct platform_device *pdev) | |||
353 | platform_set_drvdata(pdev, phy); | 400 | platform_set_drvdata(pdev, phy); |
354 | pm_runtime_enable(phy->dev); | 401 | pm_runtime_enable(phy->dev); |
355 | 402 | ||
356 | generic_phy = devm_phy_create(phy->dev, &ops, NULL); | 403 | generic_phy = devm_phy_create(phy->dev, NULL, &ops, NULL); |
357 | if (IS_ERR(generic_phy)) | 404 | if (IS_ERR(generic_phy)) |
358 | return PTR_ERR(generic_phy); | 405 | return PTR_ERR(generic_phy); |
359 | 406 | ||
@@ -387,6 +434,8 @@ static int ti_pipe3_runtime_suspend(struct device *dev) | |||
387 | clk_disable_unprepare(phy->wkupclk); | 434 | clk_disable_unprepare(phy->wkupclk); |
388 | if (!IS_ERR(phy->refclk)) | 435 | if (!IS_ERR(phy->refclk)) |
389 | clk_disable_unprepare(phy->refclk); | 436 | clk_disable_unprepare(phy->refclk); |
437 | if (!IS_ERR(phy->div_clk)) | ||
438 | clk_disable_unprepare(phy->div_clk); | ||
390 | 439 | ||
391 | return 0; | 440 | return 0; |
392 | } | 441 | } |
@@ -412,8 +461,19 @@ static int ti_pipe3_runtime_resume(struct device *dev) | |||
412 | } | 461 | } |
413 | } | 462 | } |
414 | 463 | ||
464 | if (!IS_ERR(phy->div_clk)) { | ||
465 | ret = clk_prepare_enable(phy->div_clk); | ||
466 | if (ret) { | ||
467 | dev_err(phy->dev, "Failed to enable div_clk %d\n", ret); | ||
468 | goto err3; | ||
469 | } | ||
470 | } | ||
415 | return 0; | 471 | return 0; |
416 | 472 | ||
473 | err3: | ||
474 | if (!IS_ERR(phy->wkupclk)) | ||
475 | clk_disable_unprepare(phy->wkupclk); | ||
476 | |||
417 | err2: | 477 | err2: |
418 | if (!IS_ERR(phy->refclk)) | 478 | if (!IS_ERR(phy->refclk)) |
419 | clk_disable_unprepare(phy->refclk); | 479 | clk_disable_unprepare(phy->refclk); |
@@ -446,6 +506,9 @@ static const struct of_device_id ti_pipe3_id_table[] = { | |||
446 | .compatible = "ti,phy-pipe3-sata", | 506 | .compatible = "ti,phy-pipe3-sata", |
447 | .data = dpll_map_sata, | 507 | .data = dpll_map_sata, |
448 | }, | 508 | }, |
509 | { | ||
510 | .compatible = "ti,phy-pipe3-pcie", | ||
511 | }, | ||
449 | {} | 512 | {} |
450 | }; | 513 | }; |
451 | MODULE_DEVICE_TABLE(of, ti_pipe3_id_table); | 514 | MODULE_DEVICE_TABLE(of, ti_pipe3_id_table); |
diff --git a/drivers/phy/phy-twl4030-usb.c b/drivers/phy/phy-twl4030-usb.c index 2e0e9b3774c8..e1a6623d4696 100644 --- a/drivers/phy/phy-twl4030-usb.c +++ b/drivers/phy/phy-twl4030-usb.c | |||
@@ -695,7 +695,7 @@ static int twl4030_usb_probe(struct platform_device *pdev) | |||
695 | otg->set_host = twl4030_set_host; | 695 | otg->set_host = twl4030_set_host; |
696 | otg->set_peripheral = twl4030_set_peripheral; | 696 | otg->set_peripheral = twl4030_set_peripheral; |
697 | 697 | ||
698 | phy = devm_phy_create(twl->dev, &ops, init_data); | 698 | phy = devm_phy_create(twl->dev, NULL, &ops, init_data); |
699 | if (IS_ERR(phy)) { | 699 | if (IS_ERR(phy)) { |
700 | dev_dbg(&pdev->dev, "Failed to create PHY\n"); | 700 | dev_dbg(&pdev->dev, "Failed to create PHY\n"); |
701 | return PTR_ERR(phy); | 701 | return PTR_ERR(phy); |
diff --git a/drivers/phy/phy-xgene.c b/drivers/phy/phy-xgene.c index 4aa1ccd1511f..db809b97219e 100644 --- a/drivers/phy/phy-xgene.c +++ b/drivers/phy/phy-xgene.c | |||
@@ -1707,7 +1707,7 @@ static int xgene_phy_probe(struct platform_device *pdev) | |||
1707 | ctx->dev = &pdev->dev; | 1707 | ctx->dev = &pdev->dev; |
1708 | platform_set_drvdata(pdev, ctx); | 1708 | platform_set_drvdata(pdev, ctx); |
1709 | 1709 | ||
1710 | ctx->phy = devm_phy_create(ctx->dev, &xgene_phy_ops, NULL); | 1710 | ctx->phy = devm_phy_create(ctx->dev, NULL, &xgene_phy_ops, NULL); |
1711 | if (IS_ERR(ctx->phy)) { | 1711 | if (IS_ERR(ctx->phy)) { |
1712 | dev_dbg(&pdev->dev, "Failed to create PHY\n"); | 1712 | dev_dbg(&pdev->dev, "Failed to create PHY\n"); |
1713 | rc = PTR_ERR(ctx->phy); | 1713 | rc = PTR_ERR(ctx->phy); |