aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/phy
diff options
context:
space:
mode:
authorKuninori Morimoto <kuninori.morimoto.gx@renesas.com>2012-10-31 22:03:11 -0400
committerFelipe Balbi <balbi@ti.com>2012-11-01 06:17:53 -0400
commit1789e52acc90c87484a109d6349eefe63cabb257 (patch)
tree54ad984676473cf1e0b73cf0b3557804ed5bb251 /drivers/usb/phy
parentca21dda64b756d6fe965dfe8fd0a1f320874b4b5 (diff)
usb: phy: add R-Car USB phy driver
This patch adds Renesas R-Car USB phy driver. It supports R8A7779 chip at this point. R-Car has some USB controllers, but has only one phy-initializer. So, this driver is counting users. Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> Signed-off-by: Felipe Balbi <balbi@ti.com>
Diffstat (limited to 'drivers/usb/phy')
-rw-r--r--drivers/usb/phy/Kconfig12
-rw-r--r--drivers/usb/phy/Makefile1
-rw-r--r--drivers/usb/phy/rcar-phy.c220
3 files changed, 233 insertions, 0 deletions
diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig
index 63c339b3e676..7eb73c561bd2 100644
--- a/drivers/usb/phy/Kconfig
+++ b/drivers/usb/phy/Kconfig
@@ -32,3 +32,15 @@ config MV_U3D_PHY
32 help 32 help
33 Enable this to support Marvell USB 3.0 phy controller for Marvell 33 Enable this to support Marvell USB 3.0 phy controller for Marvell
34 SoC. 34 SoC.
35
36config USB_RCAR_PHY
37 tristate "Renesas R-Car USB phy support"
38 depends on USB || USB_GADGET
39 select USB_OTG_UTILS
40 help
41 Say Y here to add support for the Renesas R-Car USB phy driver.
42 This chip is typically used as USB phy for USB host, gadget.
43 This driver supports: R8A7779
44
45 To compile this driver as a module, choose M here: the
46 module will be called rcar-phy.
diff --git a/drivers/usb/phy/Makefile b/drivers/usb/phy/Makefile
index b069f29f1225..1a579a860a03 100644
--- a/drivers/usb/phy/Makefile
+++ b/drivers/usb/phy/Makefile
@@ -8,3 +8,4 @@ obj-$(CONFIG_OMAP_USB2) += omap-usb2.o
8obj-$(CONFIG_USB_ISP1301) += isp1301.o 8obj-$(CONFIG_USB_ISP1301) += isp1301.o
9obj-$(CONFIG_MV_U3D_PHY) += mv_u3d_phy.o 9obj-$(CONFIG_MV_U3D_PHY) += mv_u3d_phy.o
10obj-$(CONFIG_USB_EHCI_TEGRA) += tegra_usb_phy.o 10obj-$(CONFIG_USB_EHCI_TEGRA) += tegra_usb_phy.o
11obj-$(CONFIG_USB_RCAR_PHY) += rcar-phy.o
diff --git a/drivers/usb/phy/rcar-phy.c b/drivers/usb/phy/rcar-phy.c
new file mode 100644
index 000000000000..792f505d630c
--- /dev/null
+++ b/drivers/usb/phy/rcar-phy.c
@@ -0,0 +1,220 @@
1/*
2 * Renesas R-Car USB phy driver
3 *
4 * Copyright (C) 2012 Renesas Solutions Corp.
5 * Kuninori Morimoto <kuninori.morimoto.gx@renesas.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/usb/otg.h>
15#include <linux/platform_device.h>
16#include <linux/spinlock.h>
17#include <linux/module.h>
18
19/* USBH common register */
20#define USBPCTRL0 0x0800
21#define USBPCTRL1 0x0804
22#define USBST 0x0808
23#define USBEH0 0x080C
24#define USBOH0 0x081C
25#define USBCTL0 0x0858
26#define EIIBC1 0x0094
27#define EIIBC2 0x009C
28
29/* USBPCTRL1 */
30#define PHY_RST (1 << 2)
31#define PLL_ENB (1 << 1)
32#define PHY_ENB (1 << 0)
33
34/* USBST */
35#define ST_ACT (1 << 31)
36#define ST_PLL (1 << 30)
37
38struct rcar_usb_phy_priv {
39 struct usb_phy phy;
40 spinlock_t lock;
41
42 void __iomem *reg0;
43 void __iomem *reg1;
44 int counter;
45};
46
47#define usb_phy_to_priv(p) container_of(p, struct rcar_usb_phy_priv, phy)
48
49
50/*
51 * USB initial/install operation.
52 *
53 * This function setup USB phy.
54 * The used value and setting order came from
55 * [USB :: Initial setting] on datasheet.
56 */
57static int rcar_usb_phy_init(struct usb_phy *phy)
58{
59 struct rcar_usb_phy_priv *priv = usb_phy_to_priv(phy);
60 struct device *dev = phy->dev;
61 void __iomem *reg0 = priv->reg0;
62 void __iomem *reg1 = priv->reg1;
63 int i;
64 u32 val;
65 unsigned long flags;
66
67 spin_lock_irqsave(&priv->lock, flags);
68 if (priv->counter++ == 0) {
69
70 /*
71 * USB phy start-up
72 */
73
74 /* (1) USB-PHY standby release */
75 iowrite32(PHY_ENB, (reg0 + USBPCTRL1));
76
77 /* (2) start USB-PHY internal PLL */
78 iowrite32(PHY_ENB | PLL_ENB, (reg0 + USBPCTRL1));
79
80 /* (3) USB module status check */
81 for (i = 0; i < 1024; i++) {
82 udelay(10);
83 val = ioread32(reg0 + USBST);
84 if (val == (ST_ACT | ST_PLL))
85 break;
86 }
87
88 if (val != (ST_ACT | ST_PLL)) {
89 dev_err(dev, "USB phy not ready\n");
90 goto phy_init_end;
91 }
92
93 /* (4) USB-PHY reset clear */
94 iowrite32(PHY_ENB | PLL_ENB | PHY_RST, (reg0 + USBPCTRL1));
95
96 /* set platform specific port settings */
97 iowrite32(0x00000000, (reg0 + USBPCTRL0));
98
99 /*
100 * EHCI IP internal buffer setting
101 * EHCI IP internal buffer enable
102 *
103 * These are recommended value of a datasheet
104 * see [USB :: EHCI internal buffer setting]
105 */
106 iowrite32(0x00ff0040, (reg0 + EIIBC1));
107 iowrite32(0x00ff0040, (reg1 + EIIBC1));
108
109 iowrite32(0x00000001, (reg0 + EIIBC2));
110 iowrite32(0x00000001, (reg1 + EIIBC2));
111
112 /*
113 * Bus alignment settings
114 */
115
116 /* (1) EHCI bus alignment (little endian) */
117 iowrite32(0x00000000, (reg0 + USBEH0));
118
119 /* (1) OHCI bus alignment (little endian) */
120 iowrite32(0x00000000, (reg0 + USBOH0));
121 }
122
123phy_init_end:
124 spin_unlock_irqrestore(&priv->lock, flags);
125
126 return 0;
127}
128
129static void rcar_usb_phy_shutdown(struct usb_phy *phy)
130{
131 struct rcar_usb_phy_priv *priv = usb_phy_to_priv(phy);
132 void __iomem *reg0 = priv->reg0;
133 unsigned long flags;
134
135 spin_lock_irqsave(&priv->lock, flags);
136
137 if (priv->counter-- == 1) { /* last user */
138 iowrite32(0x00000000, (reg0 + USBPCTRL0));
139 iowrite32(0x00000000, (reg0 + USBPCTRL1));
140 }
141
142 spin_unlock_irqrestore(&priv->lock, flags);
143}
144
145static int __devinit rcar_usb_phy_probe(struct platform_device *pdev)
146{
147 struct rcar_usb_phy_priv *priv;
148 struct resource *res0, *res1;
149 struct device *dev = &pdev->dev;
150 void __iomem *reg0, *reg1;
151 int ret;
152
153 res0 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
154 res1 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
155 if (!res0 || !res1) {
156 dev_err(dev, "Not enough platform resources\n");
157 return -EINVAL;
158 }
159
160 /*
161 * CAUTION
162 *
163 * Because this phy address is also mapped under OHCI/EHCI address area,
164 * this driver can't use devm_request_and_ioremap(dev, res) here
165 */
166 reg0 = devm_ioremap_nocache(dev, res0->start, resource_size(res0));
167 reg1 = devm_ioremap_nocache(dev, res1->start, resource_size(res1));
168 if (!reg0 || !reg1) {
169 dev_err(dev, "ioremap error\n");
170 return -ENOMEM;
171 }
172
173 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
174 if (!priv) {
175 dev_err(dev, "priv data allocation error\n");
176 return -ENOMEM;
177 }
178
179 priv->reg0 = reg0;
180 priv->reg1 = reg1;
181 priv->counter = 0;
182 priv->phy.dev = dev;
183 priv->phy.label = dev_name(dev);
184 priv->phy.init = rcar_usb_phy_init;
185 priv->phy.shutdown = rcar_usb_phy_shutdown;
186 spin_lock_init(&priv->lock);
187
188 ret = usb_add_phy(&priv->phy, USB_PHY_TYPE_USB2);
189 if (ret < 0) {
190 dev_err(dev, "usb phy addition error\n");
191 return ret;
192 }
193
194 platform_set_drvdata(pdev, priv);
195
196 return ret;
197}
198
199static int __devexit rcar_usb_phy_remove(struct platform_device *pdev)
200{
201 struct rcar_usb_phy_priv *priv = platform_get_drvdata(pdev);
202
203 usb_remove_phy(&priv->phy);
204
205 return 0;
206}
207
208static struct platform_driver rcar_usb_phy_driver = {
209 .driver = {
210 .name = "rcar_usb_phy",
211 },
212 .probe = rcar_usb_phy_probe,
213 .remove = __devexit_p(rcar_usb_phy_remove),
214};
215
216module_platform_driver(rcar_usb_phy_driver);
217
218MODULE_LICENSE("GPL v2");
219MODULE_DESCRIPTION("Renesas R-Car USB phy");
220MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");