diff options
author | Richard Zhao <richard.zhao@freescale.com> | 2012-07-07 10:56:47 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-07-09 12:59:23 -0400 |
commit | b3d99681227a8c5e1f50bccae0f55930aad2ca77 (patch) | |
tree | 0297af871a8c79f42f56453dbabe473be52455dc | |
parent | a2c3d6902f6f9916b5376c44baa8c1d08bf92a27 (diff) |
usb: otg: add basic mxs phy driver support
mxs phy is used in Freescale i.MX SoCs, for example
imx23, imx28, imx6Q. This patch adds the basic host
support.
Signed-off-by: Richard Zhao <richard.zhao@freescale.com>
Signed-off-by: Marek Vasut <marex@denx.de>
Cc: Peter Chen <peter.chen@freescale.com>
Acked-by: Felipe Balbi <balbi@ti.com>
Tested-by: Subodh Nijsure <snijsure@grid-net.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r-- | Documentation/devicetree/bindings/usb/mxs-phy.txt | 13 | ||||
-rw-r--r-- | drivers/usb/otg/Kconfig | 10 | ||||
-rw-r--r-- | drivers/usb/otg/Makefile | 1 | ||||
-rw-r--r-- | drivers/usb/otg/mxs-phy.c | 186 |
4 files changed, 210 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/usb/mxs-phy.txt b/Documentation/devicetree/bindings/usb/mxs-phy.txt new file mode 100644 index 000000000000..5835b27146ea --- /dev/null +++ b/Documentation/devicetree/bindings/usb/mxs-phy.txt | |||
@@ -0,0 +1,13 @@ | |||
1 | * Freescale MXS USB Phy Device | ||
2 | |||
3 | Required properties: | ||
4 | - compatible: Should be "fsl,imx23-usbphy" | ||
5 | - reg: Should contain registers location and length | ||
6 | - interrupts: Should contain phy interrupt | ||
7 | |||
8 | Example: | ||
9 | usbphy1: usbphy@020c9000 { | ||
10 | compatible = "fsl,imx6q-usbphy", "fsl,imx23-usbphy"; | ||
11 | reg = <0x020c9000 0x1000>; | ||
12 | interrupts = <0 44 0x04>; | ||
13 | }; | ||
diff --git a/drivers/usb/otg/Kconfig b/drivers/usb/otg/Kconfig index 5c87db06b598..13fd1ddf742f 100644 --- a/drivers/usb/otg/Kconfig +++ b/drivers/usb/otg/Kconfig | |||
@@ -116,6 +116,16 @@ config FSL_USB2_OTG | |||
116 | help | 116 | help |
117 | Enable this to support Freescale USB OTG transceiver. | 117 | Enable this to support Freescale USB OTG transceiver. |
118 | 118 | ||
119 | config USB_MXS_PHY | ||
120 | tristate "Freescale MXS USB PHY support" | ||
121 | depends on ARCH_MXC || ARCH_MXS | ||
122 | select STMP_DEVICE | ||
123 | select USB_OTG_UTILS | ||
124 | help | ||
125 | Enable this to support the Freescale MXS USB PHY. | ||
126 | |||
127 | MXS Phy is used by some of the i.MX SoCs, for example imx23/28/6x. | ||
128 | |||
119 | config USB_MV_OTG | 129 | config USB_MV_OTG |
120 | tristate "Marvell USB OTG support" | 130 | tristate "Marvell USB OTG support" |
121 | depends on USB_EHCI_MV && USB_MV_UDC && USB_SUSPEND | 131 | depends on USB_EHCI_MV && USB_MV_UDC && USB_SUSPEND |
diff --git a/drivers/usb/otg/Makefile b/drivers/usb/otg/Makefile index 41aa5098b139..a844b8d35d14 100644 --- a/drivers/usb/otg/Makefile +++ b/drivers/usb/otg/Makefile | |||
@@ -20,4 +20,5 @@ obj-$(CONFIG_USB_MSM_OTG) += msm_otg.o | |||
20 | obj-$(CONFIG_AB8500_USB) += ab8500-usb.o | 20 | obj-$(CONFIG_AB8500_USB) += ab8500-usb.o |
21 | fsl_usb2_otg-objs := fsl_otg.o otg_fsm.o | 21 | fsl_usb2_otg-objs := fsl_otg.o otg_fsm.o |
22 | obj-$(CONFIG_FSL_USB2_OTG) += fsl_usb2_otg.o | 22 | obj-$(CONFIG_FSL_USB2_OTG) += fsl_usb2_otg.o |
23 | obj-$(CONFIG_USB_MXS_PHY) += mxs-phy.o | ||
23 | obj-$(CONFIG_USB_MV_OTG) += mv_otg.o | 24 | obj-$(CONFIG_USB_MV_OTG) += mv_otg.o |
diff --git a/drivers/usb/otg/mxs-phy.c b/drivers/usb/otg/mxs-phy.c new file mode 100644 index 000000000000..c1a67cb8e244 --- /dev/null +++ b/drivers/usb/otg/mxs-phy.c | |||
@@ -0,0 +1,186 @@ | |||
1 | /* | ||
2 | * Copyright 2012 Freescale Semiconductor, Inc. | ||
3 | * Copyright (C) 2012 Marek Vasut <marex@denx.de> | ||
4 | * on behalf of DENX Software Engineering GmbH | ||
5 | * | ||
6 | * The code contained herein is licensed under the GNU General Public | ||
7 | * License. You may obtain a copy of the GNU General Public License | ||
8 | * Version 2 or later at the following locations: | ||
9 | * | ||
10 | * http://www.opensource.org/licenses/gpl-license.html | ||
11 | * http://www.gnu.org/copyleft/gpl.html | ||
12 | */ | ||
13 | |||
14 | #include <linux/module.h> | ||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/platform_device.h> | ||
17 | #include <linux/clk.h> | ||
18 | #include <linux/usb/otg.h> | ||
19 | #include <linux/stmp_device.h> | ||
20 | #include <linux/delay.h> | ||
21 | #include <linux/err.h> | ||
22 | #include <linux/io.h> | ||
23 | |||
24 | #define DRIVER_NAME "mxs_phy" | ||
25 | |||
26 | #define HW_USBPHY_PWD 0x00 | ||
27 | #define HW_USBPHY_CTRL 0x30 | ||
28 | #define HW_USBPHY_CTRL_SET 0x34 | ||
29 | #define HW_USBPHY_CTRL_CLR 0x38 | ||
30 | |||
31 | #define BM_USBPHY_CTRL_SFTRST BIT(31) | ||
32 | #define BM_USBPHY_CTRL_CLKGATE BIT(30) | ||
33 | #define BM_USBPHY_CTRL_ENUTMILEVEL3 BIT(15) | ||
34 | #define BM_USBPHY_CTRL_ENUTMILEVEL2 BIT(14) | ||
35 | #define BM_USBPHY_CTRL_ENHOSTDISCONDETECT BIT(1) | ||
36 | |||
37 | struct mxs_phy { | ||
38 | struct usb_phy phy; | ||
39 | struct clk *clk; | ||
40 | }; | ||
41 | |||
42 | #define to_mxs_phy(p) container_of((p), struct mxs_phy, phy) | ||
43 | |||
44 | static void mxs_phy_hw_init(struct mxs_phy *mxs_phy) | ||
45 | { | ||
46 | void __iomem *base = mxs_phy->phy.io_priv; | ||
47 | |||
48 | stmp_reset_block(base + HW_USBPHY_CTRL); | ||
49 | |||
50 | /* Power up the PHY */ | ||
51 | writel_relaxed(0, base + HW_USBPHY_PWD); | ||
52 | |||
53 | /* enable FS/LS device */ | ||
54 | writel_relaxed(BM_USBPHY_CTRL_ENUTMILEVEL2 | | ||
55 | BM_USBPHY_CTRL_ENUTMILEVEL3, | ||
56 | base + HW_USBPHY_CTRL_SET); | ||
57 | } | ||
58 | |||
59 | static int mxs_phy_init(struct usb_phy *phy) | ||
60 | { | ||
61 | struct mxs_phy *mxs_phy = to_mxs_phy(phy); | ||
62 | |||
63 | clk_prepare_enable(mxs_phy->clk); | ||
64 | mxs_phy_hw_init(mxs_phy); | ||
65 | |||
66 | return 0; | ||
67 | } | ||
68 | |||
69 | static void mxs_phy_shutdown(struct usb_phy *phy) | ||
70 | { | ||
71 | struct mxs_phy *mxs_phy = to_mxs_phy(phy); | ||
72 | |||
73 | writel_relaxed(BM_USBPHY_CTRL_CLKGATE, | ||
74 | phy->io_priv + HW_USBPHY_CTRL_SET); | ||
75 | |||
76 | clk_disable_unprepare(mxs_phy->clk); | ||
77 | } | ||
78 | |||
79 | static int mxs_phy_on_connect(struct usb_phy *phy, int port) | ||
80 | { | ||
81 | dev_dbg(phy->dev, "Connect on port %d\n", port); | ||
82 | |||
83 | mxs_phy_hw_init(to_mxs_phy(phy)); | ||
84 | writel_relaxed(BM_USBPHY_CTRL_ENHOSTDISCONDETECT, | ||
85 | phy->io_priv + HW_USBPHY_CTRL_SET); | ||
86 | |||
87 | return 0; | ||
88 | } | ||
89 | |||
90 | static int mxs_phy_on_disconnect(struct usb_phy *phy, int port) | ||
91 | { | ||
92 | dev_dbg(phy->dev, "Disconnect on port %d\n", port); | ||
93 | |||
94 | writel_relaxed(BM_USBPHY_CTRL_ENHOSTDISCONDETECT, | ||
95 | phy->io_priv + HW_USBPHY_CTRL_CLR); | ||
96 | |||
97 | return 0; | ||
98 | } | ||
99 | |||
100 | static int mxs_phy_probe(struct platform_device *pdev) | ||
101 | { | ||
102 | struct resource *res; | ||
103 | void __iomem *base; | ||
104 | struct clk *clk; | ||
105 | struct mxs_phy *mxs_phy; | ||
106 | |||
107 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
108 | if (!res) { | ||
109 | dev_err(&pdev->dev, "can't get device resources\n"); | ||
110 | return -ENOENT; | ||
111 | } | ||
112 | |||
113 | base = devm_request_and_ioremap(&pdev->dev, res); | ||
114 | if (!base) | ||
115 | return -EBUSY; | ||
116 | |||
117 | clk = devm_clk_get(&pdev->dev, NULL); | ||
118 | if (IS_ERR(clk)) { | ||
119 | dev_err(&pdev->dev, | ||
120 | "can't get the clock, err=%ld", PTR_ERR(clk)); | ||
121 | return PTR_ERR(clk); | ||
122 | } | ||
123 | |||
124 | mxs_phy = devm_kzalloc(&pdev->dev, sizeof(*mxs_phy), GFP_KERNEL); | ||
125 | if (!mxs_phy) { | ||
126 | dev_err(&pdev->dev, "Failed to allocate USB PHY structure!\n"); | ||
127 | return -ENOMEM; | ||
128 | } | ||
129 | |||
130 | mxs_phy->phy.io_priv = base; | ||
131 | mxs_phy->phy.dev = &pdev->dev; | ||
132 | mxs_phy->phy.label = DRIVER_NAME; | ||
133 | mxs_phy->phy.init = mxs_phy_init; | ||
134 | mxs_phy->phy.shutdown = mxs_phy_shutdown; | ||
135 | mxs_phy->phy.notify_connect = mxs_phy_on_connect; | ||
136 | mxs_phy->phy.notify_disconnect = mxs_phy_on_disconnect; | ||
137 | |||
138 | ATOMIC_INIT_NOTIFIER_HEAD(&mxs_phy->phy.notifier); | ||
139 | |||
140 | mxs_phy->clk = clk; | ||
141 | |||
142 | platform_set_drvdata(pdev, &mxs_phy->phy); | ||
143 | |||
144 | return 0; | ||
145 | } | ||
146 | |||
147 | static int __devexit mxs_phy_remove(struct platform_device *pdev) | ||
148 | { | ||
149 | platform_set_drvdata(pdev, NULL); | ||
150 | |||
151 | return 0; | ||
152 | } | ||
153 | |||
154 | static const struct of_device_id mxs_phy_dt_ids[] = { | ||
155 | { .compatible = "fsl,imx23-usbphy", }, | ||
156 | { /* sentinel */ } | ||
157 | }; | ||
158 | MODULE_DEVICE_TABLE(of, mxs_phy_dt_ids); | ||
159 | |||
160 | static struct platform_driver mxs_phy_driver = { | ||
161 | .probe = mxs_phy_probe, | ||
162 | .remove = __devexit_p(mxs_phy_remove), | ||
163 | .driver = { | ||
164 | .name = DRIVER_NAME, | ||
165 | .owner = THIS_MODULE, | ||
166 | .of_match_table = mxs_phy_dt_ids, | ||
167 | }, | ||
168 | }; | ||
169 | |||
170 | static int __init mxs_phy_module_init(void) | ||
171 | { | ||
172 | return platform_driver_register(&mxs_phy_driver); | ||
173 | } | ||
174 | postcore_initcall(mxs_phy_module_init); | ||
175 | |||
176 | static void __exit mxs_phy_module_exit(void) | ||
177 | { | ||
178 | platform_driver_unregister(&mxs_phy_driver); | ||
179 | } | ||
180 | module_exit(mxs_phy_module_exit); | ||
181 | |||
182 | MODULE_ALIAS("platform:mxs-usb-phy"); | ||
183 | MODULE_AUTHOR("Marek Vasut <marex@denx.de>"); | ||
184 | MODULE_AUTHOR("Richard Zhao <richard.zhao@freescale.com>"); | ||
185 | MODULE_DESCRIPTION("Freescale MXS USB PHY driver"); | ||
186 | MODULE_LICENSE("GPL"); | ||