diff options
-rw-r--r-- | drivers/phy/Kconfig | 6 | ||||
-rw-r--r-- | drivers/phy/Makefile | 1 | ||||
-rw-r--r-- | drivers/phy/phy-armada375-usb2.c | 158 | ||||
-rw-r--r-- | include/dt-bindings/phy/phy.h | 1 |
4 files changed, 166 insertions, 0 deletions
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index 96d43d5acc57..ccad8809ecb1 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig | |||
@@ -29,6 +29,12 @@ config PHY_BERLIN_SATA | |||
29 | help | 29 | help |
30 | Enable this to support the SATA PHY on Marvell Berlin SoCs. | 30 | Enable this to support the SATA PHY on Marvell Berlin SoCs. |
31 | 31 | ||
32 | config ARMADA375_USBCLUSTER_PHY | ||
33 | def_bool y | ||
34 | depends on MACH_ARMADA_375 || COMPILE_TEST | ||
35 | depends on OF | ||
36 | select GENERIC_PHY | ||
37 | |||
32 | config PHY_EXYNOS_MIPI_VIDEO | 38 | config PHY_EXYNOS_MIPI_VIDEO |
33 | tristate "S5P/EXYNOS SoC series MIPI CSI-2/DSI PHY driver" | 39 | tristate "S5P/EXYNOS SoC series MIPI CSI-2/DSI PHY driver" |
34 | depends on HAS_IOMEM | 40 | depends on HAS_IOMEM |
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index 68022f698f51..aa74f961e44e 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile | |||
@@ -5,6 +5,7 @@ | |||
5 | obj-$(CONFIG_GENERIC_PHY) += phy-core.o | 5 | obj-$(CONFIG_GENERIC_PHY) += phy-core.o |
6 | obj-$(CONFIG_PHY_BERLIN_USB) += phy-berlin-usb.o | 6 | obj-$(CONFIG_PHY_BERLIN_USB) += phy-berlin-usb.o |
7 | obj-$(CONFIG_PHY_BERLIN_SATA) += phy-berlin-sata.o | 7 | obj-$(CONFIG_PHY_BERLIN_SATA) += phy-berlin-sata.o |
8 | obj-$(CONFIG_ARMADA375_USBCLUSTER_PHY) += phy-armada375-usb2.o | ||
8 | obj-$(CONFIG_BCM_KONA_USB2_PHY) += phy-bcm-kona-usb2.o | 9 | obj-$(CONFIG_BCM_KONA_USB2_PHY) += phy-bcm-kona-usb2.o |
9 | obj-$(CONFIG_PHY_EXYNOS_DP_VIDEO) += phy-exynos-dp-video.o | 10 | obj-$(CONFIG_PHY_EXYNOS_DP_VIDEO) += phy-exynos-dp-video.o |
10 | obj-$(CONFIG_PHY_EXYNOS_MIPI_VIDEO) += phy-exynos-mipi-video.o | 11 | obj-$(CONFIG_PHY_EXYNOS_MIPI_VIDEO) += phy-exynos-mipi-video.o |
diff --git a/drivers/phy/phy-armada375-usb2.c b/drivers/phy/phy-armada375-usb2.c new file mode 100644 index 000000000000..ac7d99d01cb3 --- /dev/null +++ b/drivers/phy/phy-armada375-usb2.c | |||
@@ -0,0 +1,158 @@ | |||
1 | /* | ||
2 | * USB cluster support for Armada 375 platform. | ||
3 | * | ||
4 | * Copyright (C) 2014 Marvell | ||
5 | * | ||
6 | * Gregory CLEMENT <gregory.clement@free-electrons.com> | ||
7 | * | ||
8 | * This file is licensed under the terms of the GNU General Public | ||
9 | * License version 2 or later. This program is licensed "as is" | ||
10 | * without any warranty of any kind, whether express or implied. | ||
11 | * | ||
12 | * Armada 375 comes with an USB2 host and device controller and an | ||
13 | * USB3 controller. The USB cluster control register allows to manage | ||
14 | * common features of both USB controllers. | ||
15 | */ | ||
16 | |||
17 | #include <dt-bindings/phy/phy.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/io.h> | ||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/module.h> | ||
22 | #include <linux/of_address.h> | ||
23 | #include <linux/phy/phy.h> | ||
24 | #include <linux/platform_device.h> | ||
25 | |||
26 | #define USB2_PHY_CONFIG_DISABLE BIT(0) | ||
27 | |||
28 | struct armada375_cluster_phy { | ||
29 | struct phy *phy; | ||
30 | void __iomem *reg; | ||
31 | bool use_usb3; | ||
32 | int phy_provided; | ||
33 | }; | ||
34 | |||
35 | static int armada375_usb_phy_init(struct phy *phy) | ||
36 | { | ||
37 | struct armada375_cluster_phy *cluster_phy; | ||
38 | u32 reg; | ||
39 | |||
40 | cluster_phy = dev_get_drvdata(phy->dev.parent); | ||
41 | if (!cluster_phy) | ||
42 | return -ENODEV; | ||
43 | |||
44 | reg = readl(cluster_phy->reg); | ||
45 | if (cluster_phy->use_usb3) | ||
46 | reg |= USB2_PHY_CONFIG_DISABLE; | ||
47 | else | ||
48 | reg &= ~USB2_PHY_CONFIG_DISABLE; | ||
49 | writel(reg, cluster_phy->reg); | ||
50 | |||
51 | return 0; | ||
52 | } | ||
53 | |||
54 | static struct phy_ops armada375_usb_phy_ops = { | ||
55 | .init = armada375_usb_phy_init, | ||
56 | .owner = THIS_MODULE, | ||
57 | }; | ||
58 | |||
59 | /* | ||
60 | * Only one controller can use this PHY. We shouldn't have the case | ||
61 | * when two controllers want to use this PHY. But if this case occurs | ||
62 | * then we provide a phy to the first one and return an error for the | ||
63 | * next one. This error has also to be an error returned by | ||
64 | * devm_phy_optional_get() so different from ENODEV for USB2. In the | ||
65 | * USB3 case it still optional and we use ENODEV. | ||
66 | */ | ||
67 | static struct phy *armada375_usb_phy_xlate(struct device *dev, | ||
68 | struct of_phandle_args *args) | ||
69 | { | ||
70 | struct armada375_cluster_phy *cluster_phy = dev_get_drvdata(dev); | ||
71 | |||
72 | if (!cluster_phy) | ||
73 | return ERR_PTR(-ENODEV); | ||
74 | |||
75 | /* | ||
76 | * Either the phy had never been requested and then the first | ||
77 | * usb claiming it can get it, or it had already been | ||
78 | * requested in this case, we only allow to use it with the | ||
79 | * same configuration. | ||
80 | */ | ||
81 | if (WARN_ON((cluster_phy->phy_provided != PHY_NONE) && | ||
82 | (cluster_phy->phy_provided != args->args[0]))) { | ||
83 | dev_err(dev, "This PHY has already been provided!\n"); | ||
84 | dev_err(dev, "Check your device tree, only one controller can use it\n."); | ||
85 | if (args->args[0] == PHY_TYPE_USB2) | ||
86 | return ERR_PTR(-EBUSY); | ||
87 | else | ||
88 | return ERR_PTR(-ENODEV); | ||
89 | } | ||
90 | |||
91 | if (args->args[0] == PHY_TYPE_USB2) | ||
92 | cluster_phy->use_usb3 = false; | ||
93 | else if (args->args[0] == PHY_TYPE_USB3) | ||
94 | cluster_phy->use_usb3 = true; | ||
95 | else { | ||
96 | dev_err(dev, "Invalid PHY mode\n"); | ||
97 | return ERR_PTR(-ENODEV); | ||
98 | } | ||
99 | |||
100 | /* Store which phy mode is used for next test */ | ||
101 | cluster_phy->phy_provided = args->args[0]; | ||
102 | |||
103 | return cluster_phy->phy; | ||
104 | } | ||
105 | |||
106 | static int armada375_usb_phy_probe(struct platform_device *pdev) | ||
107 | { | ||
108 | struct device *dev = &pdev->dev; | ||
109 | struct phy *phy; | ||
110 | struct phy_provider *phy_provider; | ||
111 | void __iomem *usb_cluster_base; | ||
112 | struct resource *res; | ||
113 | struct armada375_cluster_phy *cluster_phy; | ||
114 | |||
115 | cluster_phy = devm_kzalloc(dev, sizeof(*cluster_phy), GFP_KERNEL); | ||
116 | if (!cluster_phy) | ||
117 | return -ENOMEM; | ||
118 | |||
119 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
120 | usb_cluster_base = devm_ioremap_resource(&pdev->dev, res); | ||
121 | if (!usb_cluster_base) | ||
122 | return -ENOMEM; | ||
123 | |||
124 | phy = devm_phy_create(dev, NULL, &armada375_usb_phy_ops); | ||
125 | if (IS_ERR(phy)) { | ||
126 | dev_err(dev, "failed to create PHY\n"); | ||
127 | return PTR_ERR(phy); | ||
128 | } | ||
129 | |||
130 | cluster_phy->phy = phy; | ||
131 | cluster_phy->reg = usb_cluster_base; | ||
132 | |||
133 | dev_set_drvdata(dev, cluster_phy); | ||
134 | |||
135 | phy_provider = devm_of_phy_provider_register(&pdev->dev, | ||
136 | armada375_usb_phy_xlate); | ||
137 | return PTR_ERR_OR_ZERO(phy_provider); | ||
138 | } | ||
139 | |||
140 | static const struct of_device_id of_usb_cluster_table[] = { | ||
141 | { .compatible = "marvell,armada-375-usb-cluster", }, | ||
142 | { /* end of list */ }, | ||
143 | }; | ||
144 | MODULE_DEVICE_TABLE(of, of_usb_cluster_table); | ||
145 | |||
146 | static struct platform_driver armada375_usb_phy_driver = { | ||
147 | .probe = armada375_usb_phy_probe, | ||
148 | .driver = { | ||
149 | .of_match_table = of_usb_cluster_table, | ||
150 | .name = "armada-375-usb-cluster", | ||
151 | .owner = THIS_MODULE, | ||
152 | } | ||
153 | }; | ||
154 | module_platform_driver(armada375_usb_phy_driver); | ||
155 | |||
156 | MODULE_DESCRIPTION("Armada 375 USB cluster driver"); | ||
157 | MODULE_AUTHOR("Gregory CLEMENT <gregory.clement@free-electrons.com>"); | ||
158 | MODULE_LICENSE("GPL"); | ||
diff --git a/include/dt-bindings/phy/phy.h b/include/dt-bindings/phy/phy.h index e8c6a3f04b85..6c901930eb3e 100644 --- a/include/dt-bindings/phy/phy.h +++ b/include/dt-bindings/phy/phy.h | |||
@@ -10,6 +10,7 @@ | |||
10 | #ifndef _DT_BINDINGS_PHY | 10 | #ifndef _DT_BINDINGS_PHY |
11 | #define _DT_BINDINGS_PHY | 11 | #define _DT_BINDINGS_PHY |
12 | 12 | ||
13 | #define PHY_NONE 0 | ||
13 | #define PHY_TYPE_SATA 1 | 14 | #define PHY_TYPE_SATA 1 |
14 | #define PHY_TYPE_PCIE 2 | 15 | #define PHY_TYPE_PCIE 2 |
15 | #define PHY_TYPE_USB2 3 | 16 | #define PHY_TYPE_USB2 3 |