]> Pileus Git - ~andy/linux/blob - drivers/usb/phy/samsung-usbphy.c
ARM: dts: exynops4210: really add universal_c210 dts
[~andy/linux] / drivers / usb / phy / samsung-usbphy.c
1 /* linux/drivers/usb/phy/samsung-usbphy.c
2  *
3  * Copyright (c) 2012 Samsung Electronics Co., Ltd.
4  *              http://www.samsung.com
5  *
6  * Author: Praveen Paneri <p.paneri@samsung.com>
7  *
8  * Samsung USB2.0 PHY transceiver; talks to S3C HS OTG controller, EHCI-S5P and
9  * OHCI-EXYNOS controllers.
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License version 2 as
13  * published by the Free Software Foundation.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  */
20
21 #include <linux/module.h>
22 #include <linux/platform_device.h>
23 #include <linux/clk.h>
24 #include <linux/delay.h>
25 #include <linux/device.h>
26 #include <linux/err.h>
27 #include <linux/io.h>
28 #include <linux/of.h>
29 #include <linux/of_address.h>
30 #include <linux/usb/otg.h>
31 #include <linux/usb/samsung_usb_phy.h>
32 #include <linux/platform_data/samsung-usbphy.h>
33
34 /* Register definitions */
35
36 #define SAMSUNG_PHYPWR                          (0x00)
37
38 #define PHYPWR_NORMAL_MASK                      (0x19 << 0)
39 #define PHYPWR_OTG_DISABLE                      (0x1 << 4)
40 #define PHYPWR_ANALOG_POWERDOWN                 (0x1 << 3)
41 #define PHYPWR_FORCE_SUSPEND                    (0x1 << 1)
42 /* For Exynos4 */
43 #define PHYPWR_NORMAL_MASK_PHY0                 (0x39 << 0)
44 #define PHYPWR_SLEEP_PHY0                       (0x1 << 5)
45
46 #define SAMSUNG_PHYCLK                          (0x04)
47
48 #define PHYCLK_MODE_USB11                       (0x1 << 6)
49 #define PHYCLK_EXT_OSC                          (0x1 << 5)
50 #define PHYCLK_COMMON_ON_N                      (0x1 << 4)
51 #define PHYCLK_ID_PULL                          (0x1 << 2)
52 #define PHYCLK_CLKSEL_MASK                      (0x3 << 0)
53 #define PHYCLK_CLKSEL_48M                       (0x0 << 0)
54 #define PHYCLK_CLKSEL_12M                       (0x2 << 0)
55 #define PHYCLK_CLKSEL_24M                       (0x3 << 0)
56
57 #define SAMSUNG_RSTCON                          (0x08)
58
59 #define RSTCON_PHYLINK_SWRST                    (0x1 << 2)
60 #define RSTCON_HLINK_SWRST                      (0x1 << 1)
61 #define RSTCON_SWRST                            (0x1 << 0)
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
161 #ifndef MHZ
162 #define MHZ (1000*1000)
163 #endif
164
165 #ifndef KHZ
166 #define KHZ (1000)
167 #endif
168
169 #define EXYNOS_USBHOST_PHY_CTRL_OFFSET          (0x4)
170 #define S3C64XX_USBPHY_ENABLE                   (0x1 << 16)
171 #define EXYNOS_USBPHY_ENABLE                    (0x1 << 0)
172 #define EXYNOS_USB20PHY_CFG_HOST_LINK           (0x1 << 0)
173
174 enum samsung_cpu_type {
175         TYPE_S3C64XX,
176         TYPE_EXYNOS4210,
177         TYPE_EXYNOS5250,
178 };
179
180 /*
181  * struct samsung_usbphy_drvdata - driver data for various SoC variants
182  * @cpu_type: machine identifier
183  * @devphy_en_mask: device phy enable mask for PHY CONTROL register
184  * @hostphy_en_mask: host phy enable mask for PHY CONTROL register
185  * @devphy_reg_offset: offset to DEVICE PHY CONTROL register from
186  *                     mapped address of system controller.
187  * @hostphy_reg_offset: offset to HOST PHY CONTROL register from
188  *                     mapped address of system controller.
189  *
190  *      Here we have a separate mask for device type phy.
191  *      Having different masks for host and device type phy helps
192  *      in setting independent masks in case of SoCs like S5PV210,
193  *      in which PHY0 and PHY1 enable bits belong to same register
194  *      placed at position 0 and 1 respectively.
195  *      Although for newer SoCs like exynos these bits belong to
196  *      different registers altogether placed at position 0.
197  */
198 struct samsung_usbphy_drvdata {
199         int cpu_type;
200         int devphy_en_mask;
201         int hostphy_en_mask;
202         u32 devphy_reg_offset;
203         u32 hostphy_reg_offset;
204 };
205
206 /*
207  * struct samsung_usbphy - transceiver driver state
208  * @phy: transceiver structure
209  * @plat: platform data
210  * @dev: The parent device supplied to the probe function
211  * @clk: usb phy clock
212  * @regs: usb phy controller registers memory base
213  * @pmuregs: USB device PHY_CONTROL register memory base
214  * @sysreg: USB2.0 PHY_CFG register memory base
215  * @ref_clk_freq: reference clock frequency selection
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
220  * @lock: lock for phy operations
221  */
222 struct samsung_usbphy {
223         struct usb_phy  phy;
224         struct samsung_usbphy_data *plat;
225         struct device   *dev;
226         struct clk      *clk;
227         void __iomem    *regs;
228         void __iomem    *pmuregs;
229         void __iomem    *sysreg;
230         int             ref_clk_freq;
231         const struct samsung_usbphy_drvdata *drv_data;
232         enum samsung_usb_phy_type phy_type;
233         atomic_t        phy_usage;
234         spinlock_t      lock;
235 };
236
237 #define phy_to_sphy(x)          container_of((x), struct samsung_usbphy, phy)
238
239 int 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
250 static int samsung_usbphy_parse_dt(struct samsung_usbphy *sphy)
251 {
252         struct device_node *usbphy_sys;
253
254         /* Getting node for system controller interface for usb-phy */
255         usbphy_sys = of_get_child_by_name(sphy->dev->of_node, "usbphy-sys");
256         if (!usbphy_sys) {
257                 dev_err(sphy->dev, "No sys-controller interface for usb-phy\n");
258                 return -ENODEV;
259         }
260
261         sphy->pmuregs = of_iomap(usbphy_sys, 0);
262
263         if (sphy->pmuregs == NULL) {
264                 dev_err(sphy->dev, "Can't get usb-phy pmu control register\n");
265                 goto err0;
266         }
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
279         return 0;
280
281 err0:
282         of_node_put(usbphy_sys);
283         return -ENXIO;
284 }
285
286 /*
287  * Set isolation here for phy.
288  * Here 'on = true' would mean USB PHY block is isolated, hence
289  * de-activated and vice-versa.
290  */
291 static void samsung_usbphy_set_isolation(struct samsung_usbphy *sphy, bool on)
292 {
293         void __iomem *reg = NULL;
294         u32 reg_val;
295         u32 en_mask = 0;
296
297         if (!sphy->pmuregs) {
298                 dev_warn(sphy->dev, "Can't set pmu isolation\n");
299                 return;
300         }
301
302         switch (sphy->drv_data->cpu_type) {
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         }
329
330         reg_val = readl(reg);
331
332         if (on)
333                 reg_val &= ~en_mask;
334         else
335                 reg_val |= en_mask;
336
337         writel(reg_val, reg);
338 }
339
340 /*
341  * Configure the mode of working of usb-phy here: HOST/DEVICE.
342  */
343 static 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  */
367 static 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 /*
378  * Returns reference clock frequency selection value
379  */
380 static int samsung_usbphy_get_refclk_freq(struct samsung_usbphy *sphy)
381 {
382         struct clk *ref_clk;
383         int refclk_freq = 0;
384
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");
393         if (IS_ERR(ref_clk)) {
394                 dev_err(sphy->dev, "Failed to get reference clock\n");
395                 return PTR_ERR(ref_clk);
396         }
397
398         if (sphy->drv_data->cpu_type == TYPE_EXYNOS5250) {
399                 /* set clock frequency for PLL */
400                 switch (clk_get_rate(ref_clk)) {
401                 case 9600 * KHZ:
402                         refclk_freq = FSEL_CLKSEL_9600K;
403                         break;
404                 case 10 * MHZ:
405                         refclk_freq = FSEL_CLKSEL_10M;
406                         break;
407                 case 12 * MHZ:
408                         refclk_freq = FSEL_CLKSEL_12M;
409                         break;
410                 case 19200 * KHZ:
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:
431                         refclk_freq = PHYCLK_CLKSEL_24M;
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                 }
443         }
444         clk_put(ref_clk);
445
446         return refclk_freq;
447 }
448
449 static 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
458 static 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
564 static void samsung_usbphy_enable(struct samsung_usbphy *sphy)
565 {
566         void __iomem *regs = sphy->regs;
567         u32 phypwr;
568         u32 phyclk;
569         u32 rstcon;
570
571         /* set clock frequency for PLL */
572         phyclk = sphy->ref_clk_freq;
573         phypwr = readl(regs + SAMSUNG_PHYPWR);
574         rstcon = readl(regs + SAMSUNG_RSTCON);
575
576         switch (sphy->drv_data->cpu_type) {
577         case TYPE_S3C64XX:
578                 phyclk &= ~PHYCLK_COMMON_ON_N;
579                 phypwr &= ~PHYPWR_NORMAL_MASK;
580                 rstcon |= RSTCON_SWRST;
581                 break;
582         case TYPE_EXYNOS4210:
583                 phypwr &= ~PHYPWR_NORMAL_MASK_PHY0;
584                 rstcon |= RSTCON_SWRST;
585         default:
586                 break;
587         }
588
589         writel(phyclk, regs + SAMSUNG_PHYCLK);
590         /* Configure PHY0 for normal operation*/
591         writel(phypwr, regs + SAMSUNG_PHYPWR);
592         /* reset all ports of PHY and Link */
593         writel(rstcon, regs + SAMSUNG_RSTCON);
594         udelay(10);
595         rstcon &= ~RSTCON_SWRST;
596         writel(rstcon, regs + SAMSUNG_RSTCON);
597 }
598
599 static 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
634 static void samsung_usbphy_disable(struct samsung_usbphy *sphy)
635 {
636         void __iomem *regs = sphy->regs;
637         u32 phypwr;
638
639         phypwr = readl(regs + SAMSUNG_PHYPWR);
640
641         switch (sphy->drv_data->cpu_type) {
642         case TYPE_S3C64XX:
643                 phypwr |= PHYPWR_NORMAL_MASK;
644                 break;
645         case TYPE_EXYNOS4210:
646                 phypwr |= PHYPWR_NORMAL_MASK_PHY0;
647         default:
648                 break;
649         }
650
651         /* Disable analog and otg block power */
652         writel(phypwr, regs + SAMSUNG_PHYPWR);
653 }
654
655 /*
656  * The function passed to the usb driver for phy initialization
657  */
658 static int samsung_usbphy_init(struct usb_phy *phy)
659 {
660         struct samsung_usbphy *sphy;
661         struct usb_bus *host = NULL;
662         unsigned long flags;
663         int ret = 0;
664
665         sphy = phy_to_sphy(phy);
666
667         host = phy->otg->host;
668
669         /* Enable the phy clock */
670         ret = clk_prepare_enable(sphy->clk);
671         if (ret) {
672                 dev_err(sphy->dev, "%s: clk_prepare_enable failed\n", __func__);
673                 return ret;
674         }
675
676         spin_lock_irqsave(&sphy->lock, flags);
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
687         /* Disable phy isolation */
688         if (sphy->plat && sphy->plat->pmu_isolation)
689                 sphy->plat->pmu_isolation(false);
690         else
691                 samsung_usbphy_set_isolation(sphy, false);
692
693         /* Selecting Host/OTG mode; After reset USB2.0PHY_CFG: HOST */
694         samsung_usbphy_cfg_sel(sphy);
695
696         /* Initialize usb phy registers */
697         if (sphy->drv_data->cpu_type == TYPE_EXYNOS5250)
698                 samsung_exynos5_usbphy_enable(sphy);
699         else
700                 samsung_usbphy_enable(sphy);
701
702         spin_unlock_irqrestore(&sphy->lock, flags);
703
704         /* Disable the phy clock */
705         clk_disable_unprepare(sphy->clk);
706
707         return ret;
708 }
709
710 /*
711  * The function passed to the usb driver for phy shutdown
712  */
713 static void samsung_usbphy_shutdown(struct usb_phy *phy)
714 {
715         struct samsung_usbphy *sphy;
716         struct usb_bus *host = NULL;
717         unsigned long flags;
718
719         sphy = phy_to_sphy(phy);
720
721         host = phy->otg->host;
722
723         if (clk_prepare_enable(sphy->clk)) {
724                 dev_err(sphy->dev, "%s: clk_prepare_enable failed\n", __func__);
725                 return;
726         }
727
728         spin_lock_irqsave(&sphy->lock, flags);
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
739         /* De-initialize usb phy registers */
740         if (sphy->drv_data->cpu_type == TYPE_EXYNOS5250)
741                 samsung_exynos5_usbphy_disable(sphy);
742         else
743                 samsung_usbphy_disable(sphy);
744
745         /* Enable phy isolation */
746         if (sphy->plat && sphy->plat->pmu_isolation)
747                 sphy->plat->pmu_isolation(true);
748         else
749                 samsung_usbphy_set_isolation(sphy, true);
750
751         spin_unlock_irqrestore(&sphy->lock, flags);
752
753         clk_disable_unprepare(sphy->clk);
754 }
755
756 static const struct of_device_id samsung_usbphy_dt_match[];
757
758 static inline const struct samsung_usbphy_drvdata
759 *samsung_usbphy_get_driver_data(struct platform_device *pdev)
760 {
761         if (pdev->dev.of_node) {
762                 const struct of_device_id *match;
763                 match = of_match_node(samsung_usbphy_dt_match,
764                                                         pdev->dev.of_node);
765                 return match->data;
766         }
767
768         return (struct samsung_usbphy_drvdata *)
769                                 platform_get_device_id(pdev)->driver_data;
770 }
771
772 static int samsung_usbphy_probe(struct platform_device *pdev)
773 {
774         struct samsung_usbphy *sphy;
775         struct usb_otg *otg;
776         struct samsung_usbphy_data *pdata = pdev->dev.platform_data;
777         const struct samsung_usbphy_drvdata *drv_data;
778         struct device *dev = &pdev->dev;
779         struct resource *phy_mem;
780         void __iomem    *phy_base;
781         struct clk *clk;
782         int ret;
783
784         phy_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
785         if (!phy_mem) {
786                 dev_err(dev, "%s: missing mem resource\n", __func__);
787                 return -ENODEV;
788         }
789
790         phy_base = devm_request_and_ioremap(dev, phy_mem);
791         if (!phy_base) {
792                 dev_err(dev, "%s: register mapping failed\n", __func__);
793                 return -ENXIO;
794         }
795
796         sphy = devm_kzalloc(dev, sizeof(*sphy), GFP_KERNEL);
797         if (!sphy)
798                 return -ENOMEM;
799
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
811         if (IS_ERR(clk)) {
812                 dev_err(dev, "Failed to get otg clock\n");
813                 return PTR_ERR(clk);
814         }
815
816         sphy->dev = dev;
817
818         if (dev->of_node) {
819                 ret = samsung_usbphy_parse_dt(sphy);
820                 if (ret < 0)
821                         return ret;
822         } else {
823                 if (!pdata) {
824                         dev_err(dev, "no platform data specified\n");
825                         return -EINVAL;
826                 }
827         }
828
829         sphy->plat              = pdata;
830         sphy->regs              = phy_base;
831         sphy->clk               = clk;
832         sphy->drv_data          = drv_data;
833         sphy->phy.dev           = sphy->dev;
834         sphy->phy.label         = "samsung-usbphy";
835         sphy->phy.init          = samsung_usbphy_init;
836         sphy->phy.shutdown      = samsung_usbphy_shutdown;
837         sphy->ref_clk_freq      = samsung_usbphy_get_refclk_freq(sphy);
838
839         sphy->phy.otg           = otg;
840         sphy->phy.otg->phy      = &sphy->phy;
841         sphy->phy.otg->set_host = samsung_usbphy_set_host;
842
843         spin_lock_init(&sphy->lock);
844
845         platform_set_drvdata(pdev, sphy);
846
847         return usb_add_phy(&sphy->phy, USB_PHY_TYPE_USB2);
848 }
849
850 static int samsung_usbphy_remove(struct platform_device *pdev)
851 {
852         struct samsung_usbphy *sphy = platform_get_drvdata(pdev);
853
854         usb_remove_phy(&sphy->phy);
855
856         if (sphy->pmuregs)
857                 iounmap(sphy->pmuregs);
858         if (sphy->sysreg)
859                 iounmap(sphy->sysreg);
860
861         return 0;
862 }
863
864 static const struct samsung_usbphy_drvdata usbphy_s3c64xx = {
865         .cpu_type               = TYPE_S3C64XX,
866         .devphy_en_mask         = S3C64XX_USBPHY_ENABLE,
867 };
868
869 static const struct samsung_usbphy_drvdata usbphy_exynos4 = {
870         .cpu_type               = TYPE_EXYNOS4210,
871         .devphy_en_mask         = EXYNOS_USBPHY_ENABLE,
872         .hostphy_en_mask        = EXYNOS_USBPHY_ENABLE,
873 };
874
875 static 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,
879 };
880
881 #ifdef CONFIG_OF
882 static const struct of_device_id samsung_usbphy_dt_match[] = {
883         {
884                 .compatible = "samsung,s3c64xx-usbphy",
885                 .data = &usbphy_s3c64xx,
886         }, {
887                 .compatible = "samsung,exynos4210-usbphy",
888                 .data = &usbphy_exynos4,
889         }, {
890                 .compatible = "samsung,exynos5250-usbphy",
891                 .data = &usbphy_exynos5
892         },
893         {},
894 };
895 MODULE_DEVICE_TABLE(of, samsung_usbphy_dt_match);
896 #endif
897
898 static struct platform_device_id samsung_usbphy_driver_ids[] = {
899         {
900                 .name           = "s3c64xx-usbphy",
901                 .driver_data    = (unsigned long)&usbphy_s3c64xx,
902         }, {
903                 .name           = "exynos4210-usbphy",
904                 .driver_data    = (unsigned long)&usbphy_exynos4,
905         }, {
906                 .name           = "exynos5250-usbphy",
907                 .driver_data    = (unsigned long)&usbphy_exynos5,
908         },
909         {},
910 };
911
912 MODULE_DEVICE_TABLE(platform, samsung_usbphy_driver_ids);
913
914 static struct platform_driver samsung_usbphy_driver = {
915         .probe          = samsung_usbphy_probe,
916         .remove         = samsung_usbphy_remove,
917         .id_table       = samsung_usbphy_driver_ids,
918         .driver         = {
919                 .name   = "samsung-usbphy",
920                 .owner  = THIS_MODULE,
921                 .of_match_table = of_match_ptr(samsung_usbphy_dt_match),
922         },
923 };
924
925 module_platform_driver(samsung_usbphy_driver);
926
927 MODULE_DESCRIPTION("Samsung USB phy controller");
928 MODULE_AUTHOR("Praveen Paneri <p.paneri@samsung.com>");
929 MODULE_LICENSE("GPL");
930 MODULE_ALIAS("platform:samsung-usbphy");