aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/zynq/patches/110-add-platform-driver-support-for-ulpi-phys.patch
blob: b2eb6aa5b7832913de4e2235654afe5469d154bf (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
--- a/drivers/usb/phy/Kconfig
+++ b/drivers/usb/phy/Kconfig
@@ -202,6 +202,7 @@ config USB_RCAR_PHY
 config USB_ULPI
 	bool "Generic ULPI Transceiver Driver"
 	depends on ARM || ARM64
+	depends on USB_PHY
 	select USB_ULPI_VIEWPORT
 	help
 	  Enable this to support ULPI connected USB OTG transceivers which
--- a/drivers/usb/phy/phy-ulpi.c
+++ b/drivers/usb/phy/phy-ulpi.c
@@ -26,9 +26,16 @@
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/export.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/io.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
 #include <linux/usb.h>
 #include <linux/usb/otg.h>
 #include <linux/usb/ulpi.h>
+#include <linux/usb/phy.h>
 
 
 struct ulpi_info {
@@ -52,6 +59,13 @@ static struct ulpi_info ulpi_ids[] = {
 	ULPI_INFO(ULPI_ID(0x0451, 0x1507), "TI TUSB1210"),
 };
 
+struct ulpi_phy {
+	struct usb_phy	*usb_phy;
+	void __iomem *regs;
+	unsigned int vp_offset;
+	unsigned int flags;
+};
+
 static int ulpi_set_otg_flags(struct usb_phy *phy)
 {
 	unsigned int flags = ULPI_OTG_CTRL_DP_PULLDOWN |
@@ -253,6 +267,23 @@ static int ulpi_set_vbus(struct usb_otg
 	return usb_phy_io_write(phy, flags, ULPI_OTG_CTRL);
 }
 
+static int usbphy_set_vbus(struct usb_phy *phy, int on)
+{
+	unsigned int flags = usb_phy_io_read(phy, ULPI_OTG_CTRL);
+
+	flags &= ~(ULPI_OTG_CTRL_DRVVBUS | ULPI_OTG_CTRL_DRVVBUS_EXT);
+
+	if (on) {
+		if (phy->flags & ULPI_OTG_DRVVBUS)
+			flags |= ULPI_OTG_CTRL_DRVVBUS;
+
+		if (phy->flags & ULPI_OTG_DRVVBUS_EXT)
+			flags |= ULPI_OTG_CTRL_DRVVBUS_EXT;
+	}
+
+	return usb_phy_io_write(phy, flags, ULPI_OTG_CTRL);
+}
+
 struct usb_phy *
 otg_ulpi_create(struct usb_phy_io_ops *ops,
 		unsigned int flags)
@@ -275,6 +306,7 @@ otg_ulpi_create(struct usb_phy_io_ops *o
 	phy->io_ops	= ops;
 	phy->otg	= otg;
 	phy->init	= ulpi_init;
+	phy->set_vbus	= usbphy_set_vbus;
 
 	otg->usb_phy	= phy;
 	otg->set_host	= ulpi_set_host;
@@ -284,3 +316,70 @@ otg_ulpi_create(struct usb_phy_io_ops *o
 }
 EXPORT_SYMBOL_GPL(otg_ulpi_create);
 
+static int ulpi_phy_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct resource *res;
+	struct ulpi_phy *uphy;
+	bool flag;
+	int ret;
+
+	uphy = devm_kzalloc(&pdev->dev, sizeof(*uphy), GFP_KERNEL);
+	if (!uphy)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	uphy->regs = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+	if (IS_ERR(uphy->regs))
+		return PTR_ERR(uphy->regs);
+
+	ret = of_property_read_u32(np, "view-port", &uphy->vp_offset);
+	if (IS_ERR(uphy->regs)) {
+		dev_err(&pdev->dev, "view-port register not specified\n");
+		return PTR_ERR(uphy->regs);
+	}
+
+	flag = of_property_read_bool(np, "drv-vbus");
+	if (flag)
+		uphy->flags |= ULPI_OTG_DRVVBUS | ULPI_OTG_DRVVBUS_EXT;
+
+	uphy->usb_phy = otg_ulpi_create(&ulpi_viewport_access_ops, uphy->flags);
+
+	uphy->usb_phy->dev = &pdev->dev;
+
+	uphy->usb_phy->io_priv = uphy->regs + uphy->vp_offset;
+
+	ret = usb_add_phy_dev(uphy->usb_phy);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int ulpi_phy_remove(struct platform_device *pdev)
+{
+	struct ulpi_phy *uphy = platform_get_drvdata(pdev);
+
+	usb_remove_phy(uphy->usb_phy);
+
+	return 0;
+}
+
+static const struct of_device_id ulpi_phy_table[] = {
+	{ .compatible = "ulpi-phy" },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, ulpi_phy_table);
+
+static struct platform_driver ulpi_phy_driver = {
+	.probe		= ulpi_phy_probe,
+	.remove		= ulpi_phy_remove,
+	.driver		= {
+		.name	= "ulpi-phy",
+		.of_match_table = ulpi_phy_table,
+	},
+};
+module_platform_driver(ulpi_phy_driver);
+
+MODULE_DESCRIPTION("ULPI PHY driver");
+MODULE_LICENSE("GPL v2");