aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/phy
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2014-08-08 14:34:32 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2014-08-08 14:34:32 -0400
commit10c8e0562057b5d64ea170feab148e1550420030 (patch)
treecfd387208c85e893c93d24e324d147eb6e9abfc9 /drivers/phy
parentd4e1f5a14e17d4f0e8034c0967511884bcb12fba (diff)
parent3e528cb7bae00ba0d73def6645d0f2fa906ee3e8 (diff)
Merge tag 'drivers-for-3.17' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
Pull ARM SoC driver changes from Olof Johansson: "A handful of driver-related changes. We've had a bunch of them going in through other branches as well, so it's only a part of what we really have this release. Larger pieces are: - Removal of a now unused PWM driver for atmel [ This includes AVR32 changes that have been appropriately acked ] - Performance counter support for the arm CCN interconnect - OMAP mailbox driver cleanups and consolidation - PCI and SATA PHY drivers for SPEAr 13xx platforms - Redefinition (with backwards compatibility!) of PCI DT bindings for Tegra to better model regulators/power" Note: this merge also fixes up the semantic conflict with the new calling convention for devm_phy_create(), see commit f0ed817638b5 ("phy: core: Let node ptr of PHY point to PHY and not of PHY provider") that came in through Greg's USB tree. Semantic merge patch by Stephen Rothwell <sfr@canb.auug.org.au> through the next tree. * tag 'drivers-for-3.17' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (38 commits) bus: arm-ccn: Fix error handling at event allocation mailbox/omap: add a parent structure for every IP instance mailbox/omap: remove the private mailbox structure mailbox/omap: consolidate OMAP mailbox driver mailbox/omap: simplify the fifo assignment by using macros mailbox/omap: remove omap_mbox_type_t from mailbox ops mailbox/omap: remove OMAP1 mailbox driver mailbox/omap: use devm_* interfaces bus: ARM CCN: add PERF_EVENTS dependency bus: ARM CCN PMU driver PCI: spear: Remove spear13xx_pcie_remove() PCI: spear: Fix Section mismatch compilation warning for probe() ARM: tegra: Remove legacy PCIe power supply properties PCI: tegra: Remove deprecated power supply properties PCI: tegra: Implement accurate power supply scheme ARM: SPEAr13xx: Update defconfigs ARM: SPEAr13xx: Add pcie and miphy DT nodes ARM: SPEAr13xx: Add bindings and dt node for misc block ARM: SPEAr13xx: Fix static mapping table phy: Add drivers for PCIe and SATA phy on SPEAr13xx ...
Diffstat (limited to 'drivers/phy')
-rw-r--r--drivers/phy/Kconfig26
-rw-r--r--drivers/phy/Makefile4
-rw-r--r--drivers/phy/phy-spear1310-miphy.c274
-rw-r--r--drivers/phy/phy-spear1340-miphy.c307
4 files changed, 603 insertions, 8 deletions
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index d1f5fc924c93..0dd742719154 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -197,13 +197,6 @@ config PHY_EXYNOS5_USBDRD
197 This driver provides PHY interface for USB 3.0 DRD controller 197 This driver provides PHY interface for USB 3.0 DRD controller
198 present on Exynos5 SoC series. 198 present on Exynos5 SoC series.
199 199
200config PHY_XGENE
201 tristate "APM X-Gene 15Gbps PHY support"
202 depends on HAS_IOMEM && OF && (ARM64 || COMPILE_TEST)
203 select GENERIC_PHY
204 help
205 This option enables support for APM X-Gene SoC multi-purpose PHY.
206
207config PHY_QCOM_APQ8064_SATA 200config PHY_QCOM_APQ8064_SATA
208 tristate "Qualcomm APQ8064 SATA SerDes/PHY driver" 201 tristate "Qualcomm APQ8064 SATA SerDes/PHY driver"
209 depends on ARCH_QCOM 202 depends on ARCH_QCOM
@@ -218,4 +211,23 @@ config PHY_QCOM_IPQ806X_SATA
218 depends on OF 211 depends on OF
219 select GENERIC_PHY 212 select GENERIC_PHY
220 213
214config PHY_ST_SPEAR1310_MIPHY
215 tristate "ST SPEAR1310-MIPHY driver"
216 select GENERIC_PHY
217 help
218 Support for ST SPEAr1310 MIPHY which can be used for PCIe and SATA.
219
220config PHY_ST_SPEAR1340_MIPHY
221 tristate "ST SPEAR1340-MIPHY driver"
222 select GENERIC_PHY
223 help
224 Support for ST SPEAr1340 MIPHY which can be used for PCIe and SATA.
225
226config 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
221endmenu 233endmenu
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index ec24e915349b..95c69ed5ed45 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -23,6 +23,8 @@ phy-exynos-usb2-$(CONFIG_PHY_EXYNOS4X12_USB2) += phy-exynos4x12-usb2.o
23phy-exynos-usb2-$(CONFIG_PHY_EXYNOS5250_USB2) += phy-exynos5250-usb2.o 23phy-exynos-usb2-$(CONFIG_PHY_EXYNOS5250_USB2) += phy-exynos5250-usb2.o
24phy-exynos-usb2-$(CONFIG_PHY_S5PV210_USB2) += phy-s5pv210-usb2.o 24phy-exynos-usb2-$(CONFIG_PHY_S5PV210_USB2) += phy-s5pv210-usb2.o
25obj-$(CONFIG_PHY_EXYNOS5_USBDRD) += phy-exynos5-usbdrd.o 25obj-$(CONFIG_PHY_EXYNOS5_USBDRD) += phy-exynos5-usbdrd.o
26obj-$(CONFIG_PHY_XGENE) += phy-xgene.o
27obj-$(CONFIG_PHY_QCOM_APQ8064_SATA) += phy-qcom-apq8064-sata.o 26obj-$(CONFIG_PHY_QCOM_APQ8064_SATA) += phy-qcom-apq8064-sata.o
28obj-$(CONFIG_PHY_QCOM_IPQ806X_SATA) += phy-qcom-ipq806x-sata.o 27obj-$(CONFIG_PHY_QCOM_IPQ806X_SATA) += phy-qcom-ipq806x-sata.o
28obj-$(CONFIG_PHY_ST_SPEAR1310_MIPHY) += phy-spear1310-miphy.o
29obj-$(CONFIG_PHY_ST_SPEAR1340_MIPHY) += phy-spear1340-miphy.o
30obj-$(CONFIG_PHY_XGENE) += phy-xgene.o
diff --git a/drivers/phy/phy-spear1310-miphy.c b/drivers/phy/phy-spear1310-miphy.c
new file mode 100644
index 000000000000..6dcbfcddb372
--- /dev/null
+++ b/drivers/phy/phy-spear1310-miphy.c
@@ -0,0 +1,274 @@
1/*
2 * ST SPEAr1310-miphy driver
3 *
4 * Copyright (C) 2014 ST Microelectronics
5 * Pratyush Anand <pratyush.anand@st.com>
6 * Mohit Kumar <mohit.kumar@st.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 *
12 */
13
14#include <linux/bitops.h>
15#include <linux/delay.h>
16#include <linux/dma-mapping.h>
17#include <linux/kernel.h>
18#include <linux/mfd/syscon.h>
19#include <linux/module.h>
20#include <linux/of_device.h>
21#include <linux/phy/phy.h>
22#include <linux/regmap.h>
23
24/* SPEAr1310 Registers */
25#define SPEAR1310_PCIE_SATA_CFG 0x3A4
26 #define SPEAR1310_PCIE_SATA2_SEL_PCIE (0 << 31)
27 #define SPEAR1310_PCIE_SATA1_SEL_PCIE (0 << 30)
28 #define SPEAR1310_PCIE_SATA0_SEL_PCIE (0 << 29)
29 #define SPEAR1310_PCIE_SATA2_SEL_SATA BIT(31)
30 #define SPEAR1310_PCIE_SATA1_SEL_SATA BIT(30)
31 #define SPEAR1310_PCIE_SATA0_SEL_SATA BIT(29)
32 #define SPEAR1310_SATA2_CFG_TX_CLK_EN BIT(27)
33 #define SPEAR1310_SATA2_CFG_RX_CLK_EN BIT(26)
34 #define SPEAR1310_SATA2_CFG_POWERUP_RESET BIT(25)
35 #define SPEAR1310_SATA2_CFG_PM_CLK_EN BIT(24)
36 #define SPEAR1310_SATA1_CFG_TX_CLK_EN BIT(23)
37 #define SPEAR1310_SATA1_CFG_RX_CLK_EN BIT(22)
38 #define SPEAR1310_SATA1_CFG_POWERUP_RESET BIT(21)
39 #define SPEAR1310_SATA1_CFG_PM_CLK_EN BIT(20)
40 #define SPEAR1310_SATA0_CFG_TX_CLK_EN BIT(19)
41 #define SPEAR1310_SATA0_CFG_RX_CLK_EN BIT(18)
42 #define SPEAR1310_SATA0_CFG_POWERUP_RESET BIT(17)
43 #define SPEAR1310_SATA0_CFG_PM_CLK_EN BIT(16)
44 #define SPEAR1310_PCIE2_CFG_DEVICE_PRESENT BIT(11)
45 #define SPEAR1310_PCIE2_CFG_POWERUP_RESET BIT(10)
46 #define SPEAR1310_PCIE2_CFG_CORE_CLK_EN BIT(9)
47 #define SPEAR1310_PCIE2_CFG_AUX_CLK_EN BIT(8)
48 #define SPEAR1310_PCIE1_CFG_DEVICE_PRESENT BIT(7)
49 #define SPEAR1310_PCIE1_CFG_POWERUP_RESET BIT(6)
50 #define SPEAR1310_PCIE1_CFG_CORE_CLK_EN BIT(5)
51 #define SPEAR1310_PCIE1_CFG_AUX_CLK_EN BIT(4)
52 #define SPEAR1310_PCIE0_CFG_DEVICE_PRESENT BIT(3)
53 #define SPEAR1310_PCIE0_CFG_POWERUP_RESET BIT(2)
54 #define SPEAR1310_PCIE0_CFG_CORE_CLK_EN BIT(1)
55 #define SPEAR1310_PCIE0_CFG_AUX_CLK_EN BIT(0)
56
57 #define SPEAR1310_PCIE_CFG_MASK(x) ((0xF << (x * 4)) | BIT((x + 29)))
58 #define SPEAR1310_SATA_CFG_MASK(x) ((0xF << (x * 4 + 16)) | \
59 BIT((x + 29)))
60 #define SPEAR1310_PCIE_CFG_VAL(x) \
61 (SPEAR1310_PCIE_SATA##x##_SEL_PCIE | \
62 SPEAR1310_PCIE##x##_CFG_AUX_CLK_EN | \
63 SPEAR1310_PCIE##x##_CFG_CORE_CLK_EN | \
64 SPEAR1310_PCIE##x##_CFG_POWERUP_RESET | \
65 SPEAR1310_PCIE##x##_CFG_DEVICE_PRESENT)
66 #define SPEAR1310_SATA_CFG_VAL(x) \
67 (SPEAR1310_PCIE_SATA##x##_SEL_SATA | \
68 SPEAR1310_SATA##x##_CFG_PM_CLK_EN | \
69 SPEAR1310_SATA##x##_CFG_POWERUP_RESET | \
70 SPEAR1310_SATA##x##_CFG_RX_CLK_EN | \
71 SPEAR1310_SATA##x##_CFG_TX_CLK_EN)
72
73#define SPEAR1310_PCIE_MIPHY_CFG_1 0x3A8
74 #define SPEAR1310_MIPHY_DUAL_OSC_BYPASS_EXT BIT(31)
75 #define SPEAR1310_MIPHY_DUAL_CLK_REF_DIV2 BIT(28)
76 #define SPEAR1310_MIPHY_DUAL_PLL_RATIO_TOP(x) (x << 16)
77 #define SPEAR1310_MIPHY_SINGLE_OSC_BYPASS_EXT BIT(15)
78 #define SPEAR1310_MIPHY_SINGLE_CLK_REF_DIV2 BIT(12)
79 #define SPEAR1310_MIPHY_SINGLE_PLL_RATIO_TOP(x) (x << 0)
80 #define SPEAR1310_PCIE_SATA_MIPHY_CFG_SATA_MASK (0xFFFF)
81 #define SPEAR1310_PCIE_SATA_MIPHY_CFG_PCIE_MASK (0xFFFF << 16)
82 #define SPEAR1310_PCIE_SATA_MIPHY_CFG_SATA \
83 (SPEAR1310_MIPHY_DUAL_OSC_BYPASS_EXT | \
84 SPEAR1310_MIPHY_DUAL_CLK_REF_DIV2 | \
85 SPEAR1310_MIPHY_DUAL_PLL_RATIO_TOP(60) | \
86 SPEAR1310_MIPHY_SINGLE_OSC_BYPASS_EXT | \
87 SPEAR1310_MIPHY_SINGLE_CLK_REF_DIV2 | \
88 SPEAR1310_MIPHY_SINGLE_PLL_RATIO_TOP(60))
89 #define SPEAR1310_PCIE_SATA_MIPHY_CFG_SATA_25M_CRYSTAL_CLK \
90 (SPEAR1310_MIPHY_SINGLE_PLL_RATIO_TOP(120))
91 #define SPEAR1310_PCIE_SATA_MIPHY_CFG_PCIE \
92 (SPEAR1310_MIPHY_DUAL_OSC_BYPASS_EXT | \
93 SPEAR1310_MIPHY_DUAL_PLL_RATIO_TOP(25) | \
94 SPEAR1310_MIPHY_SINGLE_OSC_BYPASS_EXT | \
95 SPEAR1310_MIPHY_SINGLE_PLL_RATIO_TOP(25))
96
97#define SPEAR1310_PCIE_MIPHY_CFG_2 0x3AC
98
99enum spear1310_miphy_mode {
100 SATA,
101 PCIE,
102};
103
104struct spear1310_miphy_priv {
105 /* instance id of this phy */
106 u32 id;
107 /* phy mode: 0 for SATA 1 for PCIe */
108 enum spear1310_miphy_mode mode;
109 /* regmap for any soc specific misc registers */
110 struct regmap *misc;
111 /* phy struct pointer */
112 struct phy *phy;
113};
114
115static int spear1310_miphy_pcie_init(struct spear1310_miphy_priv *priv)
116{
117 u32 val;
118
119 regmap_update_bits(priv->misc, SPEAR1310_PCIE_MIPHY_CFG_1,
120 SPEAR1310_PCIE_SATA_MIPHY_CFG_PCIE_MASK,
121 SPEAR1310_PCIE_SATA_MIPHY_CFG_PCIE);
122
123 switch (priv->id) {
124 case 0:
125 val = SPEAR1310_PCIE_CFG_VAL(0);
126 break;
127 case 1:
128 val = SPEAR1310_PCIE_CFG_VAL(1);
129 break;
130 case 2:
131 val = SPEAR1310_PCIE_CFG_VAL(2);
132 break;
133 default:
134 return -EINVAL;
135 }
136
137 regmap_update_bits(priv->misc, SPEAR1310_PCIE_SATA_CFG,
138 SPEAR1310_PCIE_CFG_MASK(priv->id), val);
139
140 return 0;
141}
142
143static int spear1310_miphy_pcie_exit(struct spear1310_miphy_priv *priv)
144{
145 regmap_update_bits(priv->misc, SPEAR1310_PCIE_SATA_CFG,
146 SPEAR1310_PCIE_CFG_MASK(priv->id), 0);
147
148 regmap_update_bits(priv->misc, SPEAR1310_PCIE_MIPHY_CFG_1,
149 SPEAR1310_PCIE_SATA_MIPHY_CFG_PCIE_MASK, 0);
150
151 return 0;
152}
153
154static int spear1310_miphy_init(struct phy *phy)
155{
156 struct spear1310_miphy_priv *priv = phy_get_drvdata(phy);
157 int ret = 0;
158
159 if (priv->mode == PCIE)
160 ret = spear1310_miphy_pcie_init(priv);
161
162 return ret;
163}
164
165static int spear1310_miphy_exit(struct phy *phy)
166{
167 struct spear1310_miphy_priv *priv = phy_get_drvdata(phy);
168 int ret = 0;
169
170 if (priv->mode == PCIE)
171 ret = spear1310_miphy_pcie_exit(priv);
172
173 return ret;
174}
175
176static const struct of_device_id spear1310_miphy_of_match[] = {
177 { .compatible = "st,spear1310-miphy" },
178 { },
179};
180MODULE_DEVICE_TABLE(of, spear1310_miphy_of_match);
181
182static struct phy_ops spear1310_miphy_ops = {
183 .init = spear1310_miphy_init,
184 .exit = spear1310_miphy_exit,
185 .owner = THIS_MODULE,
186};
187
188static struct phy *spear1310_miphy_xlate(struct device *dev,
189 struct of_phandle_args *args)
190{
191 struct spear1310_miphy_priv *priv = dev_get_drvdata(dev);
192
193 if (args->args_count < 1) {
194 dev_err(dev, "DT did not pass correct no of args\n");
195 return NULL;
196 }
197
198 priv->mode = args->args[0];
199
200 if (priv->mode != SATA && priv->mode != PCIE) {
201 dev_err(dev, "DT did not pass correct phy mode\n");
202 return NULL;
203 }
204
205 return priv->phy;
206}
207
208static int spear1310_miphy_probe(struct platform_device *pdev)
209{
210 struct device *dev = &pdev->dev;
211 struct spear1310_miphy_priv *priv;
212 struct phy_provider *phy_provider;
213
214 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
215 if (!priv) {
216 dev_err(dev, "can't alloc spear1310_miphy private date memory\n");
217 return -ENOMEM;
218 }
219
220 priv->misc =
221 syscon_regmap_lookup_by_phandle(dev->of_node, "misc");
222 if (IS_ERR(priv->misc)) {
223 dev_err(dev, "failed to find misc regmap\n");
224 return PTR_ERR(priv->misc);
225 }
226
227 if (of_property_read_u32(dev->of_node, "phy-id", &priv->id)) {
228 dev_err(dev, "failed to find phy id\n");
229 return -EINVAL;
230 }
231
232 priv->phy = devm_phy_create(dev, NULL, &spear1310_miphy_ops, NULL);
233 if (IS_ERR(priv->phy)) {
234 dev_err(dev, "failed to create SATA PCIe PHY\n");
235 return PTR_ERR(priv->phy);
236 }
237
238 dev_set_drvdata(dev, priv);
239 phy_set_drvdata(priv->phy, priv);
240
241 phy_provider =
242 devm_of_phy_provider_register(dev, spear1310_miphy_xlate);
243 if (IS_ERR(phy_provider)) {
244 dev_err(dev, "failed to register phy provider\n");
245 return PTR_ERR(phy_provider);
246 }
247
248 return 0;
249}
250
251static struct platform_driver spear1310_miphy_driver = {
252 .probe = spear1310_miphy_probe,
253 .driver = {
254 .name = "spear1310-miphy",
255 .owner = THIS_MODULE,
256 .of_match_table = of_match_ptr(spear1310_miphy_of_match),
257 },
258};
259
260static int __init spear1310_miphy_phy_init(void)
261{
262 return platform_driver_register(&spear1310_miphy_driver);
263}
264module_init(spear1310_miphy_phy_init);
265
266static void __exit spear1310_miphy_phy_exit(void)
267{
268 platform_driver_unregister(&spear1310_miphy_driver);
269}
270module_exit(spear1310_miphy_phy_exit);
271
272MODULE_DESCRIPTION("ST SPEAR1310-MIPHY driver");
273MODULE_AUTHOR("Pratyush Anand <pratyush.anand@st.com>");
274MODULE_LICENSE("GPL v2");
diff --git a/drivers/phy/phy-spear1340-miphy.c b/drivers/phy/phy-spear1340-miphy.c
new file mode 100644
index 000000000000..7135ba2603b6
--- /dev/null
+++ b/drivers/phy/phy-spear1340-miphy.c
@@ -0,0 +1,307 @@
1/*
2 * ST spear1340-miphy driver
3 *
4 * Copyright (C) 2014 ST Microelectronics
5 * Pratyush Anand <pratyush.anand@st.com>
6 * Mohit Kumar <mohit.kumar@st.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 *
12 */
13
14#include <linux/bitops.h>
15#include <linux/delay.h>
16#include <linux/dma-mapping.h>
17#include <linux/kernel.h>
18#include <linux/mfd/syscon.h>
19#include <linux/module.h>
20#include <linux/of_device.h>
21#include <linux/phy/phy.h>
22#include <linux/regmap.h>
23
24/* SPEAr1340 Registers */
25/* Power Management Registers */
26#define SPEAR1340_PCM_CFG 0x100
27 #define SPEAR1340_PCM_CFG_SATA_POWER_EN BIT(11)
28#define SPEAR1340_PCM_WKUP_CFG 0x104
29#define SPEAR1340_SWITCH_CTR 0x108
30
31#define SPEAR1340_PERIP1_SW_RST 0x318
32 #define SPEAR1340_PERIP1_SW_RSATA BIT(12)
33#define SPEAR1340_PERIP2_SW_RST 0x31C
34#define SPEAR1340_PERIP3_SW_RST 0x320
35
36/* PCIE - SATA configuration registers */
37#define SPEAR1340_PCIE_SATA_CFG 0x424
38 /* PCIE CFG MASks */
39 #define SPEAR1340_PCIE_CFG_DEVICE_PRESENT BIT(11)
40 #define SPEAR1340_PCIE_CFG_POWERUP_RESET BIT(10)
41 #define SPEAR1340_PCIE_CFG_CORE_CLK_EN BIT(9)
42 #define SPEAR1340_PCIE_CFG_AUX_CLK_EN BIT(8)
43 #define SPEAR1340_SATA_CFG_TX_CLK_EN BIT(4)
44 #define SPEAR1340_SATA_CFG_RX_CLK_EN BIT(3)
45 #define SPEAR1340_SATA_CFG_POWERUP_RESET BIT(2)
46 #define SPEAR1340_SATA_CFG_PM_CLK_EN BIT(1)
47 #define SPEAR1340_PCIE_SATA_SEL_PCIE (0)
48 #define SPEAR1340_PCIE_SATA_SEL_SATA (1)
49 #define SPEAR1340_PCIE_SATA_CFG_MASK 0xF1F
50 #define SPEAR1340_PCIE_CFG_VAL (SPEAR1340_PCIE_SATA_SEL_PCIE | \
51 SPEAR1340_PCIE_CFG_AUX_CLK_EN | \
52 SPEAR1340_PCIE_CFG_CORE_CLK_EN | \
53 SPEAR1340_PCIE_CFG_POWERUP_RESET | \
54 SPEAR1340_PCIE_CFG_DEVICE_PRESENT)
55 #define SPEAR1340_SATA_CFG_VAL (SPEAR1340_PCIE_SATA_SEL_SATA | \
56 SPEAR1340_SATA_CFG_PM_CLK_EN | \
57 SPEAR1340_SATA_CFG_POWERUP_RESET | \
58 SPEAR1340_SATA_CFG_RX_CLK_EN | \
59 SPEAR1340_SATA_CFG_TX_CLK_EN)
60
61#define SPEAR1340_PCIE_MIPHY_CFG 0x428
62 #define SPEAR1340_MIPHY_OSC_BYPASS_EXT BIT(31)
63 #define SPEAR1340_MIPHY_CLK_REF_DIV2 BIT(27)
64 #define SPEAR1340_MIPHY_CLK_REF_DIV4 (2 << 27)
65 #define SPEAR1340_MIPHY_CLK_REF_DIV8 (3 << 27)
66 #define SPEAR1340_MIPHY_PLL_RATIO_TOP(x) (x << 0)
67 #define SPEAR1340_PCIE_MIPHY_CFG_MASK 0xF80000FF
68 #define SPEAR1340_PCIE_SATA_MIPHY_CFG_SATA \
69 (SPEAR1340_MIPHY_OSC_BYPASS_EXT | \
70 SPEAR1340_MIPHY_CLK_REF_DIV2 | \
71 SPEAR1340_MIPHY_PLL_RATIO_TOP(60))
72 #define SPEAR1340_PCIE_SATA_MIPHY_CFG_SATA_25M_CRYSTAL_CLK \
73 (SPEAR1340_MIPHY_PLL_RATIO_TOP(120))
74 #define SPEAR1340_PCIE_SATA_MIPHY_CFG_PCIE \
75 (SPEAR1340_MIPHY_OSC_BYPASS_EXT | \
76 SPEAR1340_MIPHY_PLL_RATIO_TOP(25))
77
78enum spear1340_miphy_mode {
79 SATA,
80 PCIE,
81};
82
83struct spear1340_miphy_priv {
84 /* phy mode: 0 for SATA 1 for PCIe */
85 enum spear1340_miphy_mode mode;
86 /* regmap for any soc specific misc registers */
87 struct regmap *misc;
88 /* phy struct pointer */
89 struct phy *phy;
90};
91
92static int spear1340_miphy_sata_init(struct spear1340_miphy_priv *priv)
93{
94 regmap_update_bits(priv->misc, SPEAR1340_PCIE_SATA_CFG,
95 SPEAR1340_PCIE_SATA_CFG_MASK,
96 SPEAR1340_SATA_CFG_VAL);
97 regmap_update_bits(priv->misc, SPEAR1340_PCIE_MIPHY_CFG,
98 SPEAR1340_PCIE_MIPHY_CFG_MASK,
99 SPEAR1340_PCIE_SATA_MIPHY_CFG_SATA_25M_CRYSTAL_CLK);
100 /* Switch on sata power domain */
101 regmap_update_bits(priv->misc, SPEAR1340_PCM_CFG,
102 SPEAR1340_PCM_CFG_SATA_POWER_EN,
103 SPEAR1340_PCM_CFG_SATA_POWER_EN);
104 /* Wait for SATA power domain on */
105 msleep(20);
106
107 /* Disable PCIE SATA Controller reset */
108 regmap_update_bits(priv->misc, SPEAR1340_PERIP1_SW_RST,
109 SPEAR1340_PERIP1_SW_RSATA, 0);
110 /* Wait for SATA reset de-assert completion */
111 msleep(20);
112
113 return 0;
114}
115
116static int spear1340_miphy_sata_exit(struct spear1340_miphy_priv *priv)
117{
118 regmap_update_bits(priv->misc, SPEAR1340_PCIE_SATA_CFG,
119 SPEAR1340_PCIE_SATA_CFG_MASK, 0);
120 regmap_update_bits(priv->misc, SPEAR1340_PCIE_MIPHY_CFG,
121 SPEAR1340_PCIE_MIPHY_CFG_MASK, 0);
122
123 /* Enable PCIE SATA Controller reset */
124 regmap_update_bits(priv->misc, SPEAR1340_PERIP1_SW_RST,
125 SPEAR1340_PERIP1_SW_RSATA,
126 SPEAR1340_PERIP1_SW_RSATA);
127 /* Wait for SATA power domain off */
128 msleep(20);
129 /* Switch off sata power domain */
130 regmap_update_bits(priv->misc, SPEAR1340_PCM_CFG,
131 SPEAR1340_PCM_CFG_SATA_POWER_EN, 0);
132 /* Wait for SATA reset assert completion */
133 msleep(20);
134
135 return 0;
136}
137
138static int spear1340_miphy_pcie_init(struct spear1340_miphy_priv *priv)
139{
140 regmap_update_bits(priv->misc, SPEAR1340_PCIE_MIPHY_CFG,
141 SPEAR1340_PCIE_MIPHY_CFG_MASK,
142 SPEAR1340_PCIE_SATA_MIPHY_CFG_PCIE);
143 regmap_update_bits(priv->misc, SPEAR1340_PCIE_SATA_CFG,
144 SPEAR1340_PCIE_SATA_CFG_MASK,
145 SPEAR1340_PCIE_CFG_VAL);
146
147 return 0;
148}
149
150static int spear1340_miphy_pcie_exit(struct spear1340_miphy_priv *priv)
151{
152 regmap_update_bits(priv->misc, SPEAR1340_PCIE_MIPHY_CFG,
153 SPEAR1340_PCIE_MIPHY_CFG_MASK, 0);
154 regmap_update_bits(priv->misc, SPEAR1340_PCIE_SATA_CFG,
155 SPEAR1340_PCIE_SATA_CFG_MASK, 0);
156
157 return 0;
158}
159
160static int spear1340_miphy_init(struct phy *phy)
161{
162 struct spear1340_miphy_priv *priv = phy_get_drvdata(phy);
163 int ret = 0;
164
165 if (priv->mode == SATA)
166 ret = spear1340_miphy_sata_init(priv);
167 else if (priv->mode == PCIE)
168 ret = spear1340_miphy_pcie_init(priv);
169
170 return ret;
171}
172
173static int spear1340_miphy_exit(struct phy *phy)
174{
175 struct spear1340_miphy_priv *priv = phy_get_drvdata(phy);
176 int ret = 0;
177
178 if (priv->mode == SATA)
179 ret = spear1340_miphy_sata_exit(priv);
180 else if (priv->mode == PCIE)
181 ret = spear1340_miphy_pcie_exit(priv);
182
183 return ret;
184}
185
186static const struct of_device_id spear1340_miphy_of_match[] = {
187 { .compatible = "st,spear1340-miphy" },
188 { },
189};
190MODULE_DEVICE_TABLE(of, spear1340_miphy_of_match);
191
192static struct phy_ops spear1340_miphy_ops = {
193 .init = spear1340_miphy_init,
194 .exit = spear1340_miphy_exit,
195 .owner = THIS_MODULE,
196};
197
198#ifdef CONFIG_PM_SLEEP
199static int spear1340_miphy_suspend(struct device *dev)
200{
201 struct spear1340_miphy_priv *priv = dev_get_drvdata(dev);
202 int ret = 0;
203
204 if (priv->mode == SATA)
205 ret = spear1340_miphy_sata_exit(priv);
206
207 return ret;
208}
209
210static int spear1340_miphy_resume(struct device *dev)
211{
212 struct spear1340_miphy_priv *priv = dev_get_drvdata(dev);
213 int ret = 0;
214
215 if (priv->mode == SATA)
216 ret = spear1340_miphy_sata_init(priv);
217
218 return ret;
219}
220#endif
221
222static SIMPLE_DEV_PM_OPS(spear1340_miphy_pm_ops, spear1340_miphy_suspend,
223 spear1340_miphy_resume);
224
225static struct phy *spear1340_miphy_xlate(struct device *dev,
226 struct of_phandle_args *args)
227{
228 struct spear1340_miphy_priv *priv = dev_get_drvdata(dev);
229
230 if (args->args_count < 1) {
231 dev_err(dev, "DT did not pass correct no of args\n");
232 return NULL;
233 }
234
235 priv->mode = args->args[0];
236
237 if (priv->mode != SATA && priv->mode != PCIE) {
238 dev_err(dev, "DT did not pass correct phy mode\n");
239 return NULL;
240 }
241
242 return priv->phy;
243}
244
245static int spear1340_miphy_probe(struct platform_device *pdev)
246{
247 struct device *dev = &pdev->dev;
248 struct spear1340_miphy_priv *priv;
249 struct phy_provider *phy_provider;
250
251 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
252 if (!priv) {
253 dev_err(dev, "can't alloc spear1340_miphy private date memory\n");
254 return -ENOMEM;
255 }
256
257 priv->misc =
258 syscon_regmap_lookup_by_phandle(dev->of_node, "misc");
259 if (IS_ERR(priv->misc)) {
260 dev_err(dev, "failed to find misc regmap\n");
261 return PTR_ERR(priv->misc);
262 }
263
264 priv->phy = devm_phy_create(dev, NULL, &spear1340_miphy_ops, NULL);
265 if (IS_ERR(priv->phy)) {
266 dev_err(dev, "failed to create SATA PCIe PHY\n");
267 return PTR_ERR(priv->phy);
268 }
269
270 dev_set_drvdata(dev, priv);
271 phy_set_drvdata(priv->phy, priv);
272
273 phy_provider =
274 devm_of_phy_provider_register(dev, spear1340_miphy_xlate);
275 if (IS_ERR(phy_provider)) {
276 dev_err(dev, "failed to register phy provider\n");
277 return PTR_ERR(phy_provider);
278 }
279
280 return 0;
281}
282
283static struct platform_driver spear1340_miphy_driver = {
284 .probe = spear1340_miphy_probe,
285 .driver = {
286 .name = "spear1340-miphy",
287 .owner = THIS_MODULE,
288 .pm = &spear1340_miphy_pm_ops,
289 .of_match_table = of_match_ptr(spear1340_miphy_of_match),
290 },
291};
292
293static int __init spear1340_miphy_phy_init(void)
294{
295 return platform_driver_register(&spear1340_miphy_driver);
296}
297module_init(spear1340_miphy_phy_init);
298
299static void __exit spear1340_miphy_phy_exit(void)
300{
301 platform_driver_unregister(&spear1340_miphy_driver);
302}
303module_exit(spear1340_miphy_phy_exit);
304
305MODULE_DESCRIPTION("ST SPEAR1340-MIPHY driver");
306MODULE_AUTHOR("Pratyush Anand <pratyush.anand@st.com>");
307MODULE_LICENSE("GPL v2");