aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/phy
diff options
context:
space:
mode:
authorVivek Gautam <gautam.vivek@samsung.com>2013-01-22 08:00:41 -0500
committerFelipe Balbi <balbi@ti.com>2013-01-23 06:39:11 -0500
commit8c1b3e16e902b010f79e2d299927ec43b495f1c7 (patch)
tree851e81f1b30a3f63d7925ab45c8783f94f39ba65 /drivers/usb/phy
parentb506eebc504caaf863b5c5a68a1e1d304d610482 (diff)
usb: phy: samsung: Add host phy support to samsung-phy driver
This patch adds host phy support to samsung-usbphy driver and further adds support for samsung's exynos5250 usb-phy. Signed-off-by: Praveen Paneri <p.paneri@samsung.com> Signed-off-by: Vivek Gautam <gautam.vivek@samsung.com> Acked-by: Kukjin Kim <kgene.kim@samsung.com> Signed-off-by: Felipe Balbi <balbi@ti.com>
Diffstat (limited to 'drivers/usb/phy')
-rw-r--r--drivers/usb/phy/Kconfig2
-rw-r--r--drivers/usb/phy/samsung-usbphy.c513
2 files changed, 486 insertions, 29 deletions
diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig
index 36a85b675429..fae4d08c0ddd 100644
--- a/drivers/usb/phy/Kconfig
+++ b/drivers/usb/phy/Kconfig
@@ -48,7 +48,7 @@ config USB_RCAR_PHY
48 48
49config SAMSUNG_USBPHY 49config SAMSUNG_USBPHY
50 bool "Samsung USB PHY controller Driver" 50 bool "Samsung USB PHY controller Driver"
51 depends on USB_S3C_HSOTG 51 depends on USB_S3C_HSOTG || USB_EHCI_S5P || USB_OHCI_EXYNOS
52 select USB_OTG_UTILS 52 select USB_OTG_UTILS
53 help 53 help
54 Enable this to support Samsung USB phy controller for samsung 54 Enable this to support Samsung USB phy controller for samsung
diff --git a/drivers/usb/phy/samsung-usbphy.c b/drivers/usb/phy/samsung-usbphy.c
index 30aebb59d803..9e9861c673ab 100644
--- a/drivers/usb/phy/samsung-usbphy.c
+++ b/drivers/usb/phy/samsung-usbphy.c
@@ -5,7 +5,8 @@
5 * 5 *
6 * Author: Praveen Paneri <p.paneri@samsung.com> 6 * Author: Praveen Paneri <p.paneri@samsung.com>
7 * 7 *
8 * Samsung USB2.0 High-speed OTG transceiver, talks to S3C HS OTG controller 8 * Samsung USB2.0 PHY transceiver; talks to S3C HS OTG controller, EHCI-S5P and
9 * OHCI-EXYNOS controllers.
9 * 10 *
10 * This program is free software; you can redistribute it and/or modify 11 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as 12 * it under the terms of the GNU General Public License version 2 as
@@ -21,11 +22,13 @@
21#include <linux/platform_device.h> 22#include <linux/platform_device.h>
22#include <linux/clk.h> 23#include <linux/clk.h>
23#include <linux/delay.h> 24#include <linux/delay.h>
25#include <linux/device.h>
24#include <linux/err.h> 26#include <linux/err.h>
25#include <linux/io.h> 27#include <linux/io.h>
26#include <linux/of.h> 28#include <linux/of.h>
27#include <linux/of_address.h> 29#include <linux/of_address.h>
28#include <linux/usb/otg.h> 30#include <linux/usb/otg.h>
31#include <linux/usb/samsung_usb_phy.h>
29#include <linux/platform_data/samsung-usbphy.h> 32#include <linux/platform_data/samsung-usbphy.h>
30 33
31/* Register definitions */ 34/* Register definitions */
@@ -57,24 +60,132 @@
57#define RSTCON_HLINK_SWRST (0x1 << 1) 60#define RSTCON_HLINK_SWRST (0x1 << 1)
58#define RSTCON_SWRST (0x1 << 0) 61#define RSTCON_SWRST (0x1 << 0)
59 62
63/* EXYNOS5 */
64#define EXYNOS5_PHY_HOST_CTRL0 (0x00)
65
66#define HOST_CTRL0_PHYSWRSTALL (0x1 << 31)
67
68#define HOST_CTRL0_REFCLKSEL_MASK (0x3 << 19)
69#define HOST_CTRL0_REFCLKSEL_XTAL (0x0 << 19)
70#define HOST_CTRL0_REFCLKSEL_EXTL (0x1 << 19)
71#define HOST_CTRL0_REFCLKSEL_CLKCORE (0x2 << 19)
72
73#define HOST_CTRL0_FSEL_MASK (0x7 << 16)
74#define HOST_CTRL0_FSEL(_x) ((_x) << 16)
75
76#define FSEL_CLKSEL_50M (0x7)
77#define FSEL_CLKSEL_24M (0x5)
78#define FSEL_CLKSEL_20M (0x4)
79#define FSEL_CLKSEL_19200K (0x3)
80#define FSEL_CLKSEL_12M (0x2)
81#define FSEL_CLKSEL_10M (0x1)
82#define FSEL_CLKSEL_9600K (0x0)
83
84#define HOST_CTRL0_TESTBURNIN (0x1 << 11)
85#define HOST_CTRL0_RETENABLE (0x1 << 10)
86#define HOST_CTRL0_COMMONON_N (0x1 << 9)
87#define HOST_CTRL0_SIDDQ (0x1 << 6)
88#define HOST_CTRL0_FORCESLEEP (0x1 << 5)
89#define HOST_CTRL0_FORCESUSPEND (0x1 << 4)
90#define HOST_CTRL0_WORDINTERFACE (0x1 << 3)
91#define HOST_CTRL0_UTMISWRST (0x1 << 2)
92#define HOST_CTRL0_LINKSWRST (0x1 << 1)
93#define HOST_CTRL0_PHYSWRST (0x1 << 0)
94
95#define EXYNOS5_PHY_HOST_TUNE0 (0x04)
96
97#define EXYNOS5_PHY_HSIC_CTRL1 (0x10)
98
99#define EXYNOS5_PHY_HSIC_TUNE1 (0x14)
100
101#define EXYNOS5_PHY_HSIC_CTRL2 (0x20)
102
103#define EXYNOS5_PHY_HSIC_TUNE2 (0x24)
104
105#define HSIC_CTRL_REFCLKSEL_MASK (0x3 << 23)
106#define HSIC_CTRL_REFCLKSEL (0x2 << 23)
107
108#define HSIC_CTRL_REFCLKDIV_MASK (0x7f << 16)
109#define HSIC_CTRL_REFCLKDIV(_x) ((_x) << 16)
110#define HSIC_CTRL_REFCLKDIV_12 (0x24 << 16)
111#define HSIC_CTRL_REFCLKDIV_15 (0x1c << 16)
112#define HSIC_CTRL_REFCLKDIV_16 (0x1a << 16)
113#define HSIC_CTRL_REFCLKDIV_19_2 (0x15 << 16)
114#define HSIC_CTRL_REFCLKDIV_20 (0x14 << 16)
115
116#define HSIC_CTRL_SIDDQ (0x1 << 6)
117#define HSIC_CTRL_FORCESLEEP (0x1 << 5)
118#define HSIC_CTRL_FORCESUSPEND (0x1 << 4)
119#define HSIC_CTRL_WORDINTERFACE (0x1 << 3)
120#define HSIC_CTRL_UTMISWRST (0x1 << 2)
121#define HSIC_CTRL_PHYSWRST (0x1 << 0)
122
123#define EXYNOS5_PHY_HOST_EHCICTRL (0x30)
124
125#define HOST_EHCICTRL_ENAINCRXALIGN (0x1 << 29)
126#define HOST_EHCICTRL_ENAINCR4 (0x1 << 28)
127#define HOST_EHCICTRL_ENAINCR8 (0x1 << 27)
128#define HOST_EHCICTRL_ENAINCR16 (0x1 << 26)
129
130#define EXYNOS5_PHY_HOST_OHCICTRL (0x34)
131
132#define HOST_OHCICTRL_SUSPLGCY (0x1 << 3)
133#define HOST_OHCICTRL_APPSTARTCLK (0x1 << 2)
134#define HOST_OHCICTRL_CNTSEL (0x1 << 1)
135#define HOST_OHCICTRL_CLKCKTRST (0x1 << 0)
136
137#define EXYNOS5_PHY_OTG_SYS (0x38)
138
139#define OTG_SYS_PHYLINK_SWRESET (0x1 << 14)
140#define OTG_SYS_LINKSWRST_UOTG (0x1 << 13)
141#define OTG_SYS_PHY0_SWRST (0x1 << 12)
142
143#define OTG_SYS_REFCLKSEL_MASK (0x3 << 9)
144#define OTG_SYS_REFCLKSEL_XTAL (0x0 << 9)
145#define OTG_SYS_REFCLKSEL_EXTL (0x1 << 9)
146#define OTG_SYS_REFCLKSEL_CLKCORE (0x2 << 9)
147
148#define OTG_SYS_IDPULLUP_UOTG (0x1 << 8)
149#define OTG_SYS_COMMON_ON (0x1 << 7)
150
151#define OTG_SYS_FSEL_MASK (0x7 << 4)
152#define OTG_SYS_FSEL(_x) ((_x) << 4)
153
154#define OTG_SYS_FORCESLEEP (0x1 << 3)
155#define OTG_SYS_OTGDISABLE (0x1 << 2)
156#define OTG_SYS_SIDDQ_UOTG (0x1 << 1)
157#define OTG_SYS_FORCESUSPEND (0x1 << 0)
158
159#define EXYNOS5_PHY_OTG_TUNE (0x40)
160
60#ifndef MHZ 161#ifndef MHZ
61#define MHZ (1000*1000) 162#define MHZ (1000*1000)
62#endif 163#endif
63 164
165#ifndef KHZ
166#define KHZ (1000)
167#endif
168
169#define EXYNOS_USBHOST_PHY_CTRL_OFFSET (0x4)
64#define S3C64XX_USBPHY_ENABLE (0x1 << 16) 170#define S3C64XX_USBPHY_ENABLE (0x1 << 16)
65#define EXYNOS_USBPHY_ENABLE (0x1 << 0) 171#define EXYNOS_USBPHY_ENABLE (0x1 << 0)
172#define EXYNOS_USB20PHY_CFG_HOST_LINK (0x1 << 0)
66 173
67enum samsung_cpu_type { 174enum samsung_cpu_type {
68 TYPE_S3C64XX, 175 TYPE_S3C64XX,
69 TYPE_EXYNOS4210, 176 TYPE_EXYNOS4210,
177 TYPE_EXYNOS5250,
70}; 178};
71 179
72/* 180/*
73 * struct samsung_usbphy_drvdata - driver data for various SoC variants 181 * struct samsung_usbphy_drvdata - driver data for various SoC variants
74 * @cpu_type: machine identifier 182 * @cpu_type: machine identifier
75 * @devphy_en_mask: device phy enable mask for PHY CONTROL register 183 * @devphy_en_mask: device phy enable mask for PHY CONTROL register
184 * @hostphy_en_mask: host phy enable mask for PHY CONTROL register
76 * @devphy_reg_offset: offset to DEVICE PHY CONTROL register from 185 * @devphy_reg_offset: offset to DEVICE PHY CONTROL register from
77 * mapped address of system controller. 186 * mapped address of system controller.
187 * @hostphy_reg_offset: offset to HOST PHY CONTROL register from
188 * mapped address of system controller.
78 * 189 *
79 * Here we have a separate mask for device type phy. 190 * Here we have a separate mask for device type phy.
80 * Having different masks for host and device type phy helps 191 * Having different masks for host and device type phy helps
@@ -87,7 +198,9 @@ enum samsung_cpu_type {
87struct samsung_usbphy_drvdata { 198struct samsung_usbphy_drvdata {
88 int cpu_type; 199 int cpu_type;
89 int devphy_en_mask; 200 int devphy_en_mask;
201 int hostphy_en_mask;
90 u32 devphy_reg_offset; 202 u32 devphy_reg_offset;
203 u32 hostphy_reg_offset;
91}; 204};
92 205
93/* 206/*
@@ -98,8 +211,12 @@ struct samsung_usbphy_drvdata {
98 * @clk: usb phy clock 211 * @clk: usb phy clock
99 * @regs: usb phy controller registers memory base 212 * @regs: usb phy controller registers memory base
100 * @pmuregs: USB device PHY_CONTROL register memory base 213 * @pmuregs: USB device PHY_CONTROL register memory base
214 * @sysreg: USB2.0 PHY_CFG register memory base
101 * @ref_clk_freq: reference clock frequency selection 215 * @ref_clk_freq: reference clock frequency selection
102 * @drv_data: driver data available for different SoCs 216 * @drv_data: driver data available for different SoCs
217 * @phy_type: Samsung SoCs specific phy types: #HOST
218 * #DEVICE
219 * @phy_usage: usage count for phy
103 * @lock: lock for phy operations 220 * @lock: lock for phy operations
104 */ 221 */
105struct samsung_usbphy { 222struct samsung_usbphy {
@@ -109,13 +226,27 @@ struct samsung_usbphy {
109 struct clk *clk; 226 struct clk *clk;
110 void __iomem *regs; 227 void __iomem *regs;
111 void __iomem *pmuregs; 228 void __iomem *pmuregs;
229 void __iomem *sysreg;
112 int ref_clk_freq; 230 int ref_clk_freq;
113 const struct samsung_usbphy_drvdata *drv_data; 231 const struct samsung_usbphy_drvdata *drv_data;
232 enum samsung_usb_phy_type phy_type;
233 atomic_t phy_usage;
114 spinlock_t lock; 234 spinlock_t lock;
115}; 235};
116 236
117#define phy_to_sphy(x) container_of((x), struct samsung_usbphy, phy) 237#define phy_to_sphy(x) container_of((x), struct samsung_usbphy, phy)
118 238
239int samsung_usbphy_set_host(struct usb_otg *otg, struct usb_bus *host)
240{
241 if (!otg)
242 return -ENODEV;
243
244 if (!otg->host)
245 otg->host = host;
246
247 return 0;
248}
249
119static int samsung_usbphy_parse_dt(struct samsung_usbphy *sphy) 250static int samsung_usbphy_parse_dt(struct samsung_usbphy *sphy)
120{ 251{
121 struct device_node *usbphy_sys; 252 struct device_node *usbphy_sys;
@@ -129,14 +260,27 @@ static int samsung_usbphy_parse_dt(struct samsung_usbphy *sphy)
129 260
130 sphy->pmuregs = of_iomap(usbphy_sys, 0); 261 sphy->pmuregs = of_iomap(usbphy_sys, 0);
131 262
132 of_node_put(usbphy_sys);
133
134 if (sphy->pmuregs == NULL) { 263 if (sphy->pmuregs == NULL) {
135 dev_err(sphy->dev, "Can't get usb-phy pmu control register\n"); 264 dev_err(sphy->dev, "Can't get usb-phy pmu control register\n");
136 return -ENODEV; 265 goto err0;
137 } 266 }
138 267
268 sphy->sysreg = of_iomap(usbphy_sys, 1);
269
270 /*
271 * Not returning error code here, since this situation is not fatal.
272 * Few SoCs may not have this switch available
273 */
274 if (sphy->sysreg == NULL)
275 dev_warn(sphy->dev, "Can't get usb-phy sysreg cfg register\n");
276
277 of_node_put(usbphy_sys);
278
139 return 0; 279 return 0;
280
281err0:
282 of_node_put(usbphy_sys);
283 return -ENXIO;
140} 284}
141 285
142/* 286/*
@@ -146,17 +290,42 @@ static int samsung_usbphy_parse_dt(struct samsung_usbphy *sphy)
146 */ 290 */
147static void samsung_usbphy_set_isolation(struct samsung_usbphy *sphy, bool on) 291static void samsung_usbphy_set_isolation(struct samsung_usbphy *sphy, bool on)
148{ 292{
149 void __iomem *reg; 293 void __iomem *reg = NULL;
150 u32 reg_val; 294 u32 reg_val;
151 u32 en_mask; 295 u32 en_mask = 0;
152 296
153 if (!sphy->pmuregs) { 297 if (!sphy->pmuregs) {
154 dev_warn(sphy->dev, "Can't set pmu isolation\n"); 298 dev_warn(sphy->dev, "Can't set pmu isolation\n");
155 return; 299 return;
156 } 300 }
157 301
158 reg = sphy->pmuregs + sphy->drv_data->devphy_reg_offset; 302 switch (sphy->drv_data->cpu_type) {
159 en_mask = sphy->drv_data->devphy_en_mask; 303 case TYPE_S3C64XX:
304 /*
305 * Do nothing: We will add here once S3C64xx goes for DT support
306 */
307 break;
308 case TYPE_EXYNOS4210:
309 /*
310 * Fall through since exynos4210 and exynos5250 have similar
311 * register architecture: two separate registers for host and
312 * device phy control with enable bit at position 0.
313 */
314 case TYPE_EXYNOS5250:
315 if (sphy->phy_type == USB_PHY_TYPE_DEVICE) {
316 reg = sphy->pmuregs +
317 sphy->drv_data->devphy_reg_offset;
318 en_mask = sphy->drv_data->devphy_en_mask;
319 } else if (sphy->phy_type == USB_PHY_TYPE_HOST) {
320 reg = sphy->pmuregs +
321 sphy->drv_data->hostphy_reg_offset;
322 en_mask = sphy->drv_data->hostphy_en_mask;
323 }
324 break;
325 default:
326 dev_err(sphy->dev, "Invalid SoC type\n");
327 return;
328 }
160 329
161 reg_val = readl(reg); 330 reg_val = readl(reg);
162 331
@@ -169,6 +338,43 @@ static void samsung_usbphy_set_isolation(struct samsung_usbphy *sphy, bool on)
169} 338}
170 339
171/* 340/*
341 * Configure the mode of working of usb-phy here: HOST/DEVICE.
342 */
343static void samsung_usbphy_cfg_sel(struct samsung_usbphy *sphy)
344{
345 u32 reg;
346
347 if (!sphy->sysreg) {
348 dev_warn(sphy->dev, "Can't configure specified phy mode\n");
349 return;
350 }
351
352 reg = readl(sphy->sysreg);
353
354 if (sphy->phy_type == USB_PHY_TYPE_DEVICE)
355 reg &= ~EXYNOS_USB20PHY_CFG_HOST_LINK;
356 else if (sphy->phy_type == USB_PHY_TYPE_HOST)
357 reg |= EXYNOS_USB20PHY_CFG_HOST_LINK;
358
359 writel(reg, sphy->sysreg);
360}
361
362/*
363 * PHYs are different for USB Device and USB Host.
364 * This make sure that correct PHY type is selected before
365 * any operation on PHY.
366 */
367static int samsung_usbphy_set_type(struct usb_phy *phy,
368 enum samsung_usb_phy_type phy_type)
369{
370 struct samsung_usbphy *sphy = phy_to_sphy(phy);
371
372 sphy->phy_type = phy_type;
373
374 return 0;
375}
376
377/*
172 * Returns reference clock frequency selection value 378 * Returns reference clock frequency selection value
173 */ 379 */
174static int samsung_usbphy_get_refclk_freq(struct samsung_usbphy *sphy) 380static int samsung_usbphy_get_refclk_freq(struct samsung_usbphy *sphy)
@@ -176,34 +382,185 @@ static int samsung_usbphy_get_refclk_freq(struct samsung_usbphy *sphy)
176 struct clk *ref_clk; 382 struct clk *ref_clk;
177 int refclk_freq = 0; 383 int refclk_freq = 0;
178 384
179 ref_clk = clk_get(sphy->dev, "xusbxti"); 385 /*
386 * In exynos5250 USB host and device PHY use
387 * external crystal clock XXTI
388 */
389 if (sphy->drv_data->cpu_type == TYPE_EXYNOS5250)
390 ref_clk = clk_get(sphy->dev, "ext_xtal");
391 else
392 ref_clk = clk_get(sphy->dev, "xusbxti");
180 if (IS_ERR(ref_clk)) { 393 if (IS_ERR(ref_clk)) {
181 dev_err(sphy->dev, "Failed to get reference clock\n"); 394 dev_err(sphy->dev, "Failed to get reference clock\n");
182 return PTR_ERR(ref_clk); 395 return PTR_ERR(ref_clk);
183 } 396 }
184 397
185 switch (clk_get_rate(ref_clk)) { 398 if (sphy->drv_data->cpu_type == TYPE_EXYNOS5250) {
186 case 12 * MHZ: 399 /* set clock frequency for PLL */
187 refclk_freq = PHYCLK_CLKSEL_12M; 400 switch (clk_get_rate(ref_clk)) {
188 break; 401 case 9600 * KHZ:
189 case 24 * MHZ: 402 refclk_freq = FSEL_CLKSEL_9600K;
190 refclk_freq = PHYCLK_CLKSEL_24M; 403 break;
191 break; 404 case 10 * MHZ:
192 case 48 * MHZ: 405 refclk_freq = FSEL_CLKSEL_10M;
193 refclk_freq = PHYCLK_CLKSEL_48M; 406 break;
194 break; 407 case 12 * MHZ:
195 default: 408 refclk_freq = FSEL_CLKSEL_12M;
196 if (sphy->drv_data->cpu_type == TYPE_S3C64XX) 409 break;
197 refclk_freq = PHYCLK_CLKSEL_48M; 410 case 19200 * KHZ:
198 else 411 refclk_freq = FSEL_CLKSEL_19200K;
412 break;
413 case 20 * MHZ:
414 refclk_freq = FSEL_CLKSEL_20M;
415 break;
416 case 50 * MHZ:
417 refclk_freq = FSEL_CLKSEL_50M;
418 break;
419 case 24 * MHZ:
420 default:
421 /* default reference clock */
422 refclk_freq = FSEL_CLKSEL_24M;
423 break;
424 }
425 } else {
426 switch (clk_get_rate(ref_clk)) {
427 case 12 * MHZ:
428 refclk_freq = PHYCLK_CLKSEL_12M;
429 break;
430 case 24 * MHZ:
199 refclk_freq = PHYCLK_CLKSEL_24M; 431 refclk_freq = PHYCLK_CLKSEL_24M;
200 break; 432 break;
433 case 48 * MHZ:
434 refclk_freq = PHYCLK_CLKSEL_48M;
435 break;
436 default:
437 if (sphy->drv_data->cpu_type == TYPE_S3C64XX)
438 refclk_freq = PHYCLK_CLKSEL_48M;
439 else
440 refclk_freq = PHYCLK_CLKSEL_24M;
441 break;
442 }
201 } 443 }
202 clk_put(ref_clk); 444 clk_put(ref_clk);
203 445
204 return refclk_freq; 446 return refclk_freq;
205} 447}
206 448
449static bool exynos5_phyhost_is_on(void *regs)
450{
451 u32 reg;
452
453 reg = readl(regs + EXYNOS5_PHY_HOST_CTRL0);
454
455 return !(reg & HOST_CTRL0_SIDDQ);
456}
457
458static void samsung_exynos5_usbphy_enable(struct samsung_usbphy *sphy)
459{
460 void __iomem *regs = sphy->regs;
461 u32 phyclk = sphy->ref_clk_freq;
462 u32 phyhost;
463 u32 phyotg;
464 u32 phyhsic;
465 u32 ehcictrl;
466 u32 ohcictrl;
467
468 /*
469 * phy_usage helps in keeping usage count for phy
470 * so that the first consumer enabling the phy is also
471 * the last consumer to disable it.
472 */
473
474 atomic_inc(&sphy->phy_usage);
475
476 if (exynos5_phyhost_is_on(regs)) {
477 dev_info(sphy->dev, "Already power on PHY\n");
478 return;
479 }
480
481 /* Host configuration */
482 phyhost = readl(regs + EXYNOS5_PHY_HOST_CTRL0);
483
484 /* phy reference clock configuration */
485 phyhost &= ~HOST_CTRL0_FSEL_MASK;
486 phyhost |= HOST_CTRL0_FSEL(phyclk);
487
488 /* host phy reset */
489 phyhost &= ~(HOST_CTRL0_PHYSWRST |
490 HOST_CTRL0_PHYSWRSTALL |
491 HOST_CTRL0_SIDDQ |
492 /* Enable normal mode of operation */
493 HOST_CTRL0_FORCESUSPEND |
494 HOST_CTRL0_FORCESLEEP);
495
496 /* Link reset */
497 phyhost |= (HOST_CTRL0_LINKSWRST |
498 HOST_CTRL0_UTMISWRST |
499 /* COMMON Block configuration during suspend */
500 HOST_CTRL0_COMMONON_N);
501 writel(phyhost, regs + EXYNOS5_PHY_HOST_CTRL0);
502 udelay(10);
503 phyhost &= ~(HOST_CTRL0_LINKSWRST |
504 HOST_CTRL0_UTMISWRST);
505 writel(phyhost, regs + EXYNOS5_PHY_HOST_CTRL0);
506
507 /* OTG configuration */
508 phyotg = readl(regs + EXYNOS5_PHY_OTG_SYS);
509
510 /* phy reference clock configuration */
511 phyotg &= ~OTG_SYS_FSEL_MASK;
512 phyotg |= OTG_SYS_FSEL(phyclk);
513
514 /* Enable normal mode of operation */
515 phyotg &= ~(OTG_SYS_FORCESUSPEND |
516 OTG_SYS_SIDDQ_UOTG |
517 OTG_SYS_FORCESLEEP |
518 OTG_SYS_REFCLKSEL_MASK |
519 /* COMMON Block configuration during suspend */
520 OTG_SYS_COMMON_ON);
521
522 /* OTG phy & link reset */
523 phyotg |= (OTG_SYS_PHY0_SWRST |
524 OTG_SYS_LINKSWRST_UOTG |
525 OTG_SYS_PHYLINK_SWRESET |
526 OTG_SYS_OTGDISABLE |
527 /* Set phy refclk */
528 OTG_SYS_REFCLKSEL_CLKCORE);
529
530 writel(phyotg, regs + EXYNOS5_PHY_OTG_SYS);
531 udelay(10);
532 phyotg &= ~(OTG_SYS_PHY0_SWRST |
533 OTG_SYS_LINKSWRST_UOTG |
534 OTG_SYS_PHYLINK_SWRESET);
535 writel(phyotg, regs + EXYNOS5_PHY_OTG_SYS);
536
537 /* HSIC phy configuration */
538 phyhsic = (HSIC_CTRL_REFCLKDIV_12 |
539 HSIC_CTRL_REFCLKSEL |
540 HSIC_CTRL_PHYSWRST);
541 writel(phyhsic, regs + EXYNOS5_PHY_HSIC_CTRL1);
542 writel(phyhsic, regs + EXYNOS5_PHY_HSIC_CTRL2);
543 udelay(10);
544 phyhsic &= ~HSIC_CTRL_PHYSWRST;
545 writel(phyhsic, regs + EXYNOS5_PHY_HSIC_CTRL1);
546 writel(phyhsic, regs + EXYNOS5_PHY_HSIC_CTRL2);
547
548 udelay(80);
549
550 /* enable EHCI DMA burst */
551 ehcictrl = readl(regs + EXYNOS5_PHY_HOST_EHCICTRL);
552 ehcictrl |= (HOST_EHCICTRL_ENAINCRXALIGN |
553 HOST_EHCICTRL_ENAINCR4 |
554 HOST_EHCICTRL_ENAINCR8 |
555 HOST_EHCICTRL_ENAINCR16);
556 writel(ehcictrl, regs + EXYNOS5_PHY_HOST_EHCICTRL);
557
558 /* set ohci_suspend_on_n */
559 ohcictrl = readl(regs + EXYNOS5_PHY_HOST_OHCICTRL);
560 ohcictrl |= HOST_OHCICTRL_SUSPLGCY;
561 writel(ohcictrl, regs + EXYNOS5_PHY_HOST_OHCICTRL);
562}
563
207static void samsung_usbphy_enable(struct samsung_usbphy *sphy) 564static void samsung_usbphy_enable(struct samsung_usbphy *sphy)
208{ 565{
209 void __iomem *regs = sphy->regs; 566 void __iomem *regs = sphy->regs;
@@ -239,6 +596,41 @@ static void samsung_usbphy_enable(struct samsung_usbphy *sphy)
239 writel(rstcon, regs + SAMSUNG_RSTCON); 596 writel(rstcon, regs + SAMSUNG_RSTCON);
240} 597}
241 598
599static void samsung_exynos5_usbphy_disable(struct samsung_usbphy *sphy)
600{
601 void __iomem *regs = sphy->regs;
602 u32 phyhost;
603 u32 phyotg;
604 u32 phyhsic;
605
606 if (atomic_dec_return(&sphy->phy_usage) > 0) {
607 dev_info(sphy->dev, "still being used\n");
608 return;
609 }
610
611 phyhsic = (HSIC_CTRL_REFCLKDIV_12 |
612 HSIC_CTRL_REFCLKSEL |
613 HSIC_CTRL_SIDDQ |
614 HSIC_CTRL_FORCESLEEP |
615 HSIC_CTRL_FORCESUSPEND);
616 writel(phyhsic, regs + EXYNOS5_PHY_HSIC_CTRL1);
617 writel(phyhsic, regs + EXYNOS5_PHY_HSIC_CTRL2);
618
619 phyhost = readl(regs + EXYNOS5_PHY_HOST_CTRL0);
620 phyhost |= (HOST_CTRL0_SIDDQ |
621 HOST_CTRL0_FORCESUSPEND |
622 HOST_CTRL0_FORCESLEEP |
623 HOST_CTRL0_PHYSWRST |
624 HOST_CTRL0_PHYSWRSTALL);
625 writel(phyhost, regs + EXYNOS5_PHY_HOST_CTRL0);
626
627 phyotg = readl(regs + EXYNOS5_PHY_OTG_SYS);
628 phyotg |= (OTG_SYS_FORCESUSPEND |
629 OTG_SYS_SIDDQ_UOTG |
630 OTG_SYS_FORCESLEEP);
631 writel(phyotg, regs + EXYNOS5_PHY_OTG_SYS);
632}
633
242static void samsung_usbphy_disable(struct samsung_usbphy *sphy) 634static void samsung_usbphy_disable(struct samsung_usbphy *sphy)
243{ 635{
244 void __iomem *regs = sphy->regs; 636 void __iomem *regs = sphy->regs;
@@ -266,11 +658,14 @@ static void samsung_usbphy_disable(struct samsung_usbphy *sphy)
266static int samsung_usbphy_init(struct usb_phy *phy) 658static int samsung_usbphy_init(struct usb_phy *phy)
267{ 659{
268 struct samsung_usbphy *sphy; 660 struct samsung_usbphy *sphy;
661 struct usb_bus *host = NULL;
269 unsigned long flags; 662 unsigned long flags;
270 int ret = 0; 663 int ret = 0;
271 664
272 sphy = phy_to_sphy(phy); 665 sphy = phy_to_sphy(phy);
273 666
667 host = phy->otg->host;
668
274 /* Enable the phy clock */ 669 /* Enable the phy clock */
275 ret = clk_prepare_enable(sphy->clk); 670 ret = clk_prepare_enable(sphy->clk);
276 if (ret) { 671 if (ret) {
@@ -280,19 +675,35 @@ static int samsung_usbphy_init(struct usb_phy *phy)
280 675
281 spin_lock_irqsave(&sphy->lock, flags); 676 spin_lock_irqsave(&sphy->lock, flags);
282 677
678 if (host) {
679 /* setting default phy-type for USB 2.0 */
680 if (!strstr(dev_name(host->controller), "ehci") ||
681 !strstr(dev_name(host->controller), "ohci"))
682 samsung_usbphy_set_type(&sphy->phy, USB_PHY_TYPE_HOST);
683 } else {
684 samsung_usbphy_set_type(&sphy->phy, USB_PHY_TYPE_DEVICE);
685 }
686
283 /* Disable phy isolation */ 687 /* Disable phy isolation */
284 if (sphy->plat && sphy->plat->pmu_isolation) 688 if (sphy->plat && sphy->plat->pmu_isolation)
285 sphy->plat->pmu_isolation(false); 689 sphy->plat->pmu_isolation(false);
286 else 690 else
287 samsung_usbphy_set_isolation(sphy, false); 691 samsung_usbphy_set_isolation(sphy, false);
288 692
693 /* Selecting Host/OTG mode; After reset USB2.0PHY_CFG: HOST */
694 samsung_usbphy_cfg_sel(sphy);
695
289 /* Initialize usb phy registers */ 696 /* Initialize usb phy registers */
290 samsung_usbphy_enable(sphy); 697 if (sphy->drv_data->cpu_type == TYPE_EXYNOS5250)
698 samsung_exynos5_usbphy_enable(sphy);
699 else
700 samsung_usbphy_enable(sphy);
291 701
292 spin_unlock_irqrestore(&sphy->lock, flags); 702 spin_unlock_irqrestore(&sphy->lock, flags);
293 703
294 /* Disable the phy clock */ 704 /* Disable the phy clock */
295 clk_disable_unprepare(sphy->clk); 705 clk_disable_unprepare(sphy->clk);
706
296 return ret; 707 return ret;
297} 708}
298 709
@@ -302,10 +713,13 @@ static int samsung_usbphy_init(struct usb_phy *phy)
302static void samsung_usbphy_shutdown(struct usb_phy *phy) 713static void samsung_usbphy_shutdown(struct usb_phy *phy)
303{ 714{
304 struct samsung_usbphy *sphy; 715 struct samsung_usbphy *sphy;
716 struct usb_bus *host = NULL;
305 unsigned long flags; 717 unsigned long flags;
306 718
307 sphy = phy_to_sphy(phy); 719 sphy = phy_to_sphy(phy);
308 720
721 host = phy->otg->host;
722
309 if (clk_prepare_enable(sphy->clk)) { 723 if (clk_prepare_enable(sphy->clk)) {
310 dev_err(sphy->dev, "%s: clk_prepare_enable failed\n", __func__); 724 dev_err(sphy->dev, "%s: clk_prepare_enable failed\n", __func__);
311 return; 725 return;
@@ -313,8 +727,20 @@ static void samsung_usbphy_shutdown(struct usb_phy *phy)
313 727
314 spin_lock_irqsave(&sphy->lock, flags); 728 spin_lock_irqsave(&sphy->lock, flags);
315 729
730 if (host) {
731 /* setting default phy-type for USB 2.0 */
732 if (!strstr(dev_name(host->controller), "ehci") ||
733 !strstr(dev_name(host->controller), "ohci"))
734 samsung_usbphy_set_type(&sphy->phy, USB_PHY_TYPE_HOST);
735 } else {
736 samsung_usbphy_set_type(&sphy->phy, USB_PHY_TYPE_DEVICE);
737 }
738
316 /* De-initialize usb phy registers */ 739 /* De-initialize usb phy registers */
317 samsung_usbphy_disable(sphy); 740 if (sphy->drv_data->cpu_type == TYPE_EXYNOS5250)
741 samsung_exynos5_usbphy_disable(sphy);
742 else
743 samsung_usbphy_disable(sphy);
318 744
319 /* Enable phy isolation */ 745 /* Enable phy isolation */
320 if (sphy->plat && sphy->plat->pmu_isolation) 746 if (sphy->plat && sphy->plat->pmu_isolation)
@@ -346,7 +772,9 @@ static inline const struct samsung_usbphy_drvdata
346static int __devinit samsung_usbphy_probe(struct platform_device *pdev) 772static int __devinit samsung_usbphy_probe(struct platform_device *pdev)
347{ 773{
348 struct samsung_usbphy *sphy; 774 struct samsung_usbphy *sphy;
775 struct usb_otg *otg;
349 struct samsung_usbphy_data *pdata = pdev->dev.platform_data; 776 struct samsung_usbphy_data *pdata = pdev->dev.platform_data;
777 const struct samsung_usbphy_drvdata *drv_data;
350 struct device *dev = &pdev->dev; 778 struct device *dev = &pdev->dev;
351 struct resource *phy_mem; 779 struct resource *phy_mem;
352 void __iomem *phy_base; 780 void __iomem *phy_base;
@@ -369,7 +797,17 @@ static int __devinit samsung_usbphy_probe(struct platform_device *pdev)
369 if (!sphy) 797 if (!sphy)
370 return -ENOMEM; 798 return -ENOMEM;
371 799
372 clk = devm_clk_get(dev, "otg"); 800 otg = devm_kzalloc(dev, sizeof(*otg), GFP_KERNEL);
801 if (!otg)
802 return -ENOMEM;
803
804 drv_data = samsung_usbphy_get_driver_data(pdev);
805
806 if (drv_data->cpu_type == TYPE_EXYNOS5250)
807 clk = devm_clk_get(dev, "usbhost");
808 else
809 clk = devm_clk_get(dev, "otg");
810
373 if (IS_ERR(clk)) { 811 if (IS_ERR(clk)) {
374 dev_err(dev, "Failed to get otg clock\n"); 812 dev_err(dev, "Failed to get otg clock\n");
375 return PTR_ERR(clk); 813 return PTR_ERR(clk);
@@ -391,13 +829,17 @@ static int __devinit samsung_usbphy_probe(struct platform_device *pdev)
391 sphy->plat = pdata; 829 sphy->plat = pdata;
392 sphy->regs = phy_base; 830 sphy->regs = phy_base;
393 sphy->clk = clk; 831 sphy->clk = clk;
832 sphy->drv_data = drv_data;
394 sphy->phy.dev = sphy->dev; 833 sphy->phy.dev = sphy->dev;
395 sphy->phy.label = "samsung-usbphy"; 834 sphy->phy.label = "samsung-usbphy";
396 sphy->phy.init = samsung_usbphy_init; 835 sphy->phy.init = samsung_usbphy_init;
397 sphy->phy.shutdown = samsung_usbphy_shutdown; 836 sphy->phy.shutdown = samsung_usbphy_shutdown;
398 sphy->drv_data = samsung_usbphy_get_driver_data(pdev);
399 sphy->ref_clk_freq = samsung_usbphy_get_refclk_freq(sphy); 837 sphy->ref_clk_freq = samsung_usbphy_get_refclk_freq(sphy);
400 838
839 sphy->phy.otg = otg;
840 sphy->phy.otg->phy = &sphy->phy;
841 sphy->phy.otg->set_host = samsung_usbphy_set_host;
842
401 spin_lock_init(&sphy->lock); 843 spin_lock_init(&sphy->lock);
402 844
403 platform_set_drvdata(pdev, sphy); 845 platform_set_drvdata(pdev, sphy);
@@ -413,6 +855,8 @@ static int __exit samsung_usbphy_remove(struct platform_device *pdev)
413 855
414 if (sphy->pmuregs) 856 if (sphy->pmuregs)
415 iounmap(sphy->pmuregs); 857 iounmap(sphy->pmuregs);
858 if (sphy->sysreg)
859 iounmap(sphy->sysreg);
416 860
417 return 0; 861 return 0;
418} 862}
@@ -425,6 +869,13 @@ static const struct samsung_usbphy_drvdata usbphy_s3c64xx = {
425static const struct samsung_usbphy_drvdata usbphy_exynos4 = { 869static const struct samsung_usbphy_drvdata usbphy_exynos4 = {
426 .cpu_type = TYPE_EXYNOS4210, 870 .cpu_type = TYPE_EXYNOS4210,
427 .devphy_en_mask = EXYNOS_USBPHY_ENABLE, 871 .devphy_en_mask = EXYNOS_USBPHY_ENABLE,
872 .hostphy_en_mask = EXYNOS_USBPHY_ENABLE,
873};
874
875static struct samsung_usbphy_drvdata usbphy_exynos5 = {
876 .cpu_type = TYPE_EXYNOS5250,
877 .hostphy_en_mask = EXYNOS_USBPHY_ENABLE,
878 .hostphy_reg_offset = EXYNOS_USBHOST_PHY_CTRL_OFFSET,
428}; 879};
429 880
430#ifdef CONFIG_OF 881#ifdef CONFIG_OF
@@ -435,6 +886,9 @@ static const struct of_device_id samsung_usbphy_dt_match[] = {
435 }, { 886 }, {
436 .compatible = "samsung,exynos4210-usbphy", 887 .compatible = "samsung,exynos4210-usbphy",
437 .data = &usbphy_exynos4, 888 .data = &usbphy_exynos4,
889 }, {
890 .compatible = "samsung,exynos5250-usbphy",
891 .data = &usbphy_exynos5
438 }, 892 },
439 {}, 893 {},
440}; 894};
@@ -448,6 +902,9 @@ static struct platform_device_id samsung_usbphy_driver_ids[] = {
448 }, { 902 }, {
449 .name = "exynos4210-usbphy", 903 .name = "exynos4210-usbphy",
450 .driver_data = (unsigned long)&usbphy_exynos4, 904 .driver_data = (unsigned long)&usbphy_exynos4,
905 }, {
906 .name = "exynos5250-usbphy",
907 .driver_data = (unsigned long)&usbphy_exynos5,
451 }, 908 },
452 {}, 909 {},
453}; 910};