Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
mv_u3d_phy.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2011 Marvell International Ltd. All rights reserved.
3  *
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms and conditions of the GNU General Public License,
6  * version 2, as published by the Free Software Foundation.
7  */
8 
9 #include <linux/module.h>
10 #include <linux/platform_device.h>
11 #include <linux/clk.h>
12 #include <linux/delay.h>
13 #include <linux/err.h>
14 #include <linux/io.h>
15 #include <linux/usb/otg.h>
17 
18 #include "mv_u3d_phy.h"
19 
20 /*
21  * struct mv_u3d_phy - transceiver driver state
22  * @phy: transceiver structure
23  * @dev: The parent device supplied to the probe function
24  * @clk: usb phy clock
25  * @base: usb phy register memory base
26  */
27 struct mv_u3d_phy {
28  struct usb_phy phy;
30  struct device *dev;
31  struct clk *clk;
32  void __iomem *base;
33 };
34 
35 static u32 mv_u3d_phy_read(void __iomem *base, u32 reg)
36 {
37  void __iomem *addr, *data;
38 
39  addr = base;
40  data = base + 0x4;
41 
42  writel_relaxed(reg, addr);
43  return readl_relaxed(data);
44 }
45 
46 static void mv_u3d_phy_set(void __iomem *base, u32 reg, u32 value)
47 {
48  void __iomem *addr, *data;
49  u32 tmp;
50 
51  addr = base;
52  data = base + 0x4;
53 
54  writel_relaxed(reg, addr);
55  tmp = readl_relaxed(data);
56  tmp |= value;
57  writel_relaxed(tmp, data);
58 }
59 
60 static void mv_u3d_phy_clear(void __iomem *base, u32 reg, u32 value)
61 {
62  void __iomem *addr, *data;
63  u32 tmp;
64 
65  addr = base;
66  data = base + 0x4;
67 
68  writel_relaxed(reg, addr);
69  tmp = readl_relaxed(data);
70  tmp &= ~value;
71  writel_relaxed(tmp, data);
72 }
73 
74 static void mv_u3d_phy_write(void __iomem *base, u32 reg, u32 value)
75 {
76  void __iomem *addr, *data;
77 
78  addr = base;
79  data = base + 0x4;
80 
81  writel_relaxed(reg, addr);
82  writel_relaxed(value, data);
83 }
84 
86 {
87  struct mv_u3d_phy *mv_u3d_phy;
88  void __iomem *base;
89  u32 val;
90 
91  mv_u3d_phy = container_of(phy, struct mv_u3d_phy, phy);
92  base = mv_u3d_phy->base;
93 
94  /* Power down Reference Analog current, bit 15
95  * Power down PLL, bit 14
96  * Power down Receiver, bit 13
97  * Power down Transmitter, bit 12
98  * of USB3_POWER_PLL_CONTROL register
99  */
100  val = mv_u3d_phy_read(base, USB3_POWER_PLL_CONTROL);
101  val &= ~(USB3_POWER_PLL_CONTROL_PU);
102  mv_u3d_phy_write(base, USB3_POWER_PLL_CONTROL, val);
103 
104  if (mv_u3d_phy->clk)
105  clk_disable(mv_u3d_phy->clk);
106 }
107 
108 static int mv_u3d_phy_init(struct usb_phy *phy)
109 {
110  struct mv_u3d_phy *mv_u3d_phy;
111  void __iomem *base;
112  u32 val, count;
113 
114  /* enable usb3 phy */
115  mv_u3d_phy = container_of(phy, struct mv_u3d_phy, phy);
116 
117  if (mv_u3d_phy->clk)
118  clk_enable(mv_u3d_phy->clk);
119 
120  base = mv_u3d_phy->base;
121 
122  val = mv_u3d_phy_read(base, USB3_POWER_PLL_CONTROL);
124  val |= 0xF << USB3_POWER_PLL_CONTROL_PU_SHIFT;
125  mv_u3d_phy_write(base, USB3_POWER_PLL_CONTROL, val);
126  udelay(100);
127 
128  mv_u3d_phy_write(base, USB3_RESET_CONTROL,
130  udelay(100);
131 
132  mv_u3d_phy_write(base, USB3_RESET_CONTROL,
135  udelay(100);
136 
137  val = mv_u3d_phy_read(base, USB3_POWER_PLL_CONTROL);
142  mv_u3d_phy_write(base, USB3_POWER_PLL_CONTROL, val);
143  udelay(100);
144 
145  mv_u3d_phy_clear(base, USB3_KVCO_CALI_CONTROL,
147  udelay(100);
148 
149  val = mv_u3d_phy_read(base, USB3_SQUELCH_FFE);
153  val |= ((0xD << USB3_SQUELCH_FFE_FFE_CAP_SEL_SHIFT)
156  mv_u3d_phy_write(base, USB3_SQUELCH_FFE, val);
157  udelay(100);
158 
159  val = mv_u3d_phy_read(base, USB3_GEN1_SET0);
162  mv_u3d_phy_write(base, USB3_GEN1_SET0, val);
163  udelay(100);
164 
165  val = mv_u3d_phy_read(base, USB3_GEN2_SET0);
169  val |= ((0x14 << USB3_GEN2_SET0_G2_TX_AMP_SHIFT)
173  mv_u3d_phy_write(base, USB3_GEN2_SET0, val);
174  udelay(100);
175 
176  mv_u3d_phy_read(base, USB3_TX_EMPPH);
177  val &= ~(USB3_TX_EMPPH_AMP_MASK
182  val |= ((0xB << USB3_TX_EMPPH_AMP_SHIFT)
183  | (1 << USB3_TX_EMPPH_EN_SHIFT)
185  | (0x1C << USB3_TX_EMPPH_PAR1_SHIFT)
186  | (1 << USB3_TX_EMPPH_PAR2_SHIFT));
187 
188  mv_u3d_phy_write(base, USB3_TX_EMPPH, val);
189  udelay(100);
190 
191  val = mv_u3d_phy_read(base, USB3_GEN2_SET1);
200  mv_u3d_phy_write(base, USB3_GEN2_SET1, val);
201  udelay(100);
202 
203  val = mv_u3d_phy_read(base, USB3_DIGITAL_LOOPBACK_EN);
206  mv_u3d_phy_write(base, USB3_DIGITAL_LOOPBACK_EN, val);
207  udelay(100);
208 
209  val = mv_u3d_phy_read(base, USB3_IMPEDANCE_TX_SSC);
212  mv_u3d_phy_write(base, USB3_IMPEDANCE_TX_SSC, val);
213  udelay(100);
214 
215  val = mv_u3d_phy_read(base, USB3_IMPEDANCE_CALI_CTRL);
218  mv_u3d_phy_write(base, USB3_IMPEDANCE_CALI_CTRL, val);
219  udelay(100);
220 
221  val = mv_u3d_phy_read(base, USB3_PHY_ISOLATION_MODE);
227  mv_u3d_phy_write(base, USB3_PHY_ISOLATION_MODE, val);
228  udelay(100);
229 
230  val = mv_u3d_phy_read(base, USB3_TXDETRX);
231  val &= ~(USB3_TXDETRX_VTHSEL_MASK);
232  val |= 0x1 << USB3_TXDETRX_VTHSEL_SHIFT;
233  mv_u3d_phy_write(base, USB3_TXDETRX, val);
234  udelay(100);
235 
236  dev_dbg(mv_u3d_phy->dev, "start calibration\n");
237 
238 calstart:
239  /* Perform Manual Calibration */
240  mv_u3d_phy_set(base, USB3_KVCO_CALI_CONTROL,
242 
243  mdelay(1);
244 
245  count = 0;
246  while (1) {
247  val = mv_u3d_phy_read(base, USB3_KVCO_CALI_CONTROL);
248  if (val & (1 << USB3_KVCO_CALI_CONTROL_CAL_DONE_SHIFT))
249  break;
250  else if (count > 50) {
251  dev_dbg(mv_u3d_phy->dev, "calibration failure, retry...\n");
252  goto calstart;
253  }
254  count++;
255  mdelay(1);
256  }
257 
258  /* active PIPE interface */
259  mv_u3d_phy_write(base, USB3_PIPE_SM_CTRL,
261 
262  return 0;
263 }
264 
265 static int __devinit mv_u3d_phy_probe(struct platform_device *pdev)
266 {
267  struct mv_u3d_phy *mv_u3d_phy;
268  struct mv_usb_platform_data *pdata;
269  struct device *dev = &pdev->dev;
270  struct resource *res;
271  void __iomem *phy_base;
272  int ret;
273 
274  pdata = pdev->dev.platform_data;
275  if (!pdata) {
276  dev_err(&pdev->dev, "%s: no platform data defined\n", __func__);
277  return -EINVAL;
278  }
279 
280  res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
281  if (!res) {
282  dev_err(dev, "missing mem resource\n");
283  return -ENODEV;
284  }
285 
286  phy_base = devm_request_and_ioremap(dev, res);
287  if (!phy_base) {
288  dev_err(dev, "%s: register mapping failed\n", __func__);
289  return -ENXIO;
290  }
291 
292  mv_u3d_phy = devm_kzalloc(dev, sizeof(*mv_u3d_phy), GFP_KERNEL);
293  if (!mv_u3d_phy)
294  return -ENOMEM;
295 
296  mv_u3d_phy->dev = &pdev->dev;
297  mv_u3d_phy->plat = pdata;
298  mv_u3d_phy->base = phy_base;
299  mv_u3d_phy->phy.dev = mv_u3d_phy->dev;
300  mv_u3d_phy->phy.label = "mv-u3d-phy";
301  mv_u3d_phy->phy.init = mv_u3d_phy_init;
302  mv_u3d_phy->phy.shutdown = mv_u3d_phy_shutdown;
303 
304  ret = usb_add_phy(&mv_u3d_phy->phy, USB_PHY_TYPE_USB3);
305  if (ret)
306  goto err;
307 
308  if (!mv_u3d_phy->clk)
309  mv_u3d_phy->clk = clk_get(mv_u3d_phy->dev, "u3dphy");
310 
311  platform_set_drvdata(pdev, mv_u3d_phy);
312 
313  dev_info(&pdev->dev, "Initialized Marvell USB 3.0 PHY\n");
314 err:
315  return ret;
316 }
317 
318 static int __exit mv_u3d_phy_remove(struct platform_device *pdev)
319 {
320  struct mv_u3d_phy *mv_u3d_phy = platform_get_drvdata(pdev);
321 
322  usb_remove_phy(&mv_u3d_phy->phy);
323 
324  if (mv_u3d_phy->clk) {
325  clk_put(mv_u3d_phy->clk);
326  mv_u3d_phy->clk = NULL;
327  }
328 
329  return 0;
330 }
331 
332 static struct platform_driver mv_u3d_phy_driver = {
333  .probe = mv_u3d_phy_probe,
334  .remove = __devexit_p(mv_u3d_phy_remove),
335  .driver = {
336  .name = "mv-u3d-phy",
337  .owner = THIS_MODULE,
338  },
339 };
340 
341 module_platform_driver(mv_u3d_phy_driver);
342 MODULE_DESCRIPTION("Marvell USB 3.0 PHY controller");
344 MODULE_LICENSE("GPL");
345 MODULE_ALIAS("platform:mv-u3d-phy");