diff options
author | Felipe Balbi <balbi@ti.com> | 2013-03-07 10:37:59 -0500 |
---|---|---|
committer | Felipe Balbi <balbi@ti.com> | 2013-03-18 05:18:08 -0400 |
commit | 94ae98433a397dd4695652fc62ca7bc784b08216 (patch) | |
tree | 4ab764590b2ae6a8535d8b773ac80d18535e58d3 /drivers/usb/phy/phy-rcar-usb.c | |
parent | fd891498751f53dda3733d9e9ff8a1f6ea16c5e5 (diff) |
usb: phy: rename all phy drivers to phy-$name-usb.c
this will make sure that we have sensible names
for all phy drivers. Current situation was already
quite bad with too generic names being used.
Signed-off-by: Felipe Balbi <balbi@ti.com>
Diffstat (limited to 'drivers/usb/phy/phy-rcar-usb.c')
-rw-r--r-- | drivers/usb/phy/phy-rcar-usb.c | 220 |
1 files changed, 220 insertions, 0 deletions
diff --git a/drivers/usb/phy/phy-rcar-usb.c b/drivers/usb/phy/phy-rcar-usb.c new file mode 100644 index 000000000000..a35681b0c501 --- /dev/null +++ b/drivers/usb/phy/phy-rcar-usb.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 | |||
38 | struct 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 | */ | ||
57 | static 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 | |||
123 | phy_init_end: | ||
124 | spin_unlock_irqrestore(&priv->lock, flags); | ||
125 | |||
126 | return 0; | ||
127 | } | ||
128 | |||
129 | static 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 | |||
145 | static int 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 | |||
199 | static int 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 | |||
208 | static struct platform_driver rcar_usb_phy_driver = { | ||
209 | .driver = { | ||
210 | .name = "rcar_usb_phy", | ||
211 | }, | ||
212 | .probe = rcar_usb_phy_probe, | ||
213 | .remove = rcar_usb_phy_remove, | ||
214 | }; | ||
215 | |||
216 | module_platform_driver(rcar_usb_phy_driver); | ||
217 | |||
218 | MODULE_LICENSE("GPL v2"); | ||
219 | MODULE_DESCRIPTION("Renesas R-Car USB phy"); | ||
220 | MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>"); | ||