aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLubomir Rintel <lkundrak@v3.sk>2018-10-15 10:45:38 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2018-10-18 13:44:39 -0400
commit644930cbad32c0a850aaeed11eb2a49b492bf51a (patch)
tree3fb7855f47388fd6d6070a9e3dac4dbd69621db5
parent89303c7ea770b6010943ef4ed73eb92bdc5a7ec8 (diff)
phy: phy-pxa-usb: add a new driver
Turned from arch/arm/mach-mmp/devices.c into a proper PHY driver, so that in can be instantiated from a DT. Acked-by: Kishon Vijay Abraham I <kishon@ti.com> Signed-off-by: Lubomir Rintel <lkundrak@v3.sk> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/phy/marvell/Kconfig11
-rw-r--r--drivers/phy/marvell/Makefile1
-rw-r--r--drivers/phy/marvell/phy-pxa-usb.c345
3 files changed, 357 insertions, 0 deletions
diff --git a/drivers/phy/marvell/Kconfig b/drivers/phy/marvell/Kconfig
index 68e321225400..6fb4b56e4c14 100644
--- a/drivers/phy/marvell/Kconfig
+++ b/drivers/phy/marvell/Kconfig
@@ -59,3 +59,14 @@ config PHY_PXA_28NM_USB2
59 The PHY driver will be used by Marvell udc/ehci/otg driver. 59 The PHY driver will be used by Marvell udc/ehci/otg driver.
60 60
61 To compile this driver as a module, choose M here. 61 To compile this driver as a module, choose M here.
62
63config PHY_PXA_USB
64 tristate "Marvell PXA USB PHY Driver"
65 depends on ARCH_PXA || ARCH_MMP
66 select GENERIC_PHY
67 help
68 Enable this to support Marvell PXA USB PHY driver for Marvell
69 SoC. This driver will do the PHY initialization and shutdown.
70 The PHY driver will be used by Marvell udc/ehci/otg driver.
71
72 To compile this driver as a module, choose M here.
diff --git a/drivers/phy/marvell/Makefile b/drivers/phy/marvell/Makefile
index 5c3ec5d10e0d..3975b144f8ec 100644
--- a/drivers/phy/marvell/Makefile
+++ b/drivers/phy/marvell/Makefile
@@ -6,3 +6,4 @@ obj-$(CONFIG_PHY_MVEBU_CP110_COMPHY) += phy-mvebu-cp110-comphy.o
6obj-$(CONFIG_PHY_MVEBU_SATA) += phy-mvebu-sata.o 6obj-$(CONFIG_PHY_MVEBU_SATA) += phy-mvebu-sata.o
7obj-$(CONFIG_PHY_PXA_28NM_HSIC) += phy-pxa-28nm-hsic.o 7obj-$(CONFIG_PHY_PXA_28NM_HSIC) += phy-pxa-28nm-hsic.o
8obj-$(CONFIG_PHY_PXA_28NM_USB2) += phy-pxa-28nm-usb2.o 8obj-$(CONFIG_PHY_PXA_28NM_USB2) += phy-pxa-28nm-usb2.o
9obj-$(CONFIG_PHY_PXA_USB) += phy-pxa-usb.o
diff --git a/drivers/phy/marvell/phy-pxa-usb.c b/drivers/phy/marvell/phy-pxa-usb.c
new file mode 100644
index 000000000000..87ff7550b912
--- /dev/null
+++ b/drivers/phy/marvell/phy-pxa-usb.c
@@ -0,0 +1,345 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (C) 2011 Marvell International Ltd. All rights reserved.
4 * Copyright (C) 2018 Lubomir Rintel <lkundrak@v3.sk>
5 */
6
7#include <dt-bindings/phy/phy.h>
8#include <linux/clk.h>
9#include <linux/delay.h>
10#include <linux/io.h>
11#include <linux/module.h>
12#include <linux/of_address.h>
13#include <linux/phy/phy.h>
14#include <linux/platform_device.h>
15
16/* phy regs */
17#define UTMI_REVISION 0x0
18#define UTMI_CTRL 0x4
19#define UTMI_PLL 0x8
20#define UTMI_TX 0xc
21#define UTMI_RX 0x10
22#define UTMI_IVREF 0x14
23#define UTMI_T0 0x18
24#define UTMI_T1 0x1c
25#define UTMI_T2 0x20
26#define UTMI_T3 0x24
27#define UTMI_T4 0x28
28#define UTMI_T5 0x2c
29#define UTMI_RESERVE 0x30
30#define UTMI_USB_INT 0x34
31#define UTMI_DBG_CTL 0x38
32#define UTMI_OTG_ADDON 0x3c
33
34/* For UTMICTRL Register */
35#define UTMI_CTRL_USB_CLK_EN (1 << 31)
36/* pxa168 */
37#define UTMI_CTRL_SUSPEND_SET1 (1 << 30)
38#define UTMI_CTRL_SUSPEND_SET2 (1 << 29)
39#define UTMI_CTRL_RXBUF_PDWN (1 << 24)
40#define UTMI_CTRL_TXBUF_PDWN (1 << 11)
41
42#define UTMI_CTRL_INPKT_DELAY_SHIFT 30
43#define UTMI_CTRL_INPKT_DELAY_SOF_SHIFT 28
44#define UTMI_CTRL_PU_REF_SHIFT 20
45#define UTMI_CTRL_ARC_PULLDN_SHIFT 12
46#define UTMI_CTRL_PLL_PWR_UP_SHIFT 1
47#define UTMI_CTRL_PWR_UP_SHIFT 0
48
49/* For UTMI_PLL Register */
50#define UTMI_PLL_PLLCALI12_SHIFT 29
51#define UTMI_PLL_PLLCALI12_MASK (0x3 << 29)
52
53#define UTMI_PLL_PLLVDD18_SHIFT 27
54#define UTMI_PLL_PLLVDD18_MASK (0x3 << 27)
55
56#define UTMI_PLL_PLLVDD12_SHIFT 25
57#define UTMI_PLL_PLLVDD12_MASK (0x3 << 25)
58
59#define UTMI_PLL_CLK_BLK_EN_SHIFT 24
60#define CLK_BLK_EN (0x1 << 24)
61#define PLL_READY (0x1 << 23)
62#define KVCO_EXT (0x1 << 22)
63#define VCOCAL_START (0x1 << 21)
64
65#define UTMI_PLL_KVCO_SHIFT 15
66#define UTMI_PLL_KVCO_MASK (0x7 << 15)
67
68#define UTMI_PLL_ICP_SHIFT 12
69#define UTMI_PLL_ICP_MASK (0x7 << 12)
70
71#define UTMI_PLL_FBDIV_SHIFT 4
72#define UTMI_PLL_FBDIV_MASK (0xFF << 4)
73
74#define UTMI_PLL_REFDIV_SHIFT 0
75#define UTMI_PLL_REFDIV_MASK (0xF << 0)
76
77/* For UTMI_TX Register */
78#define UTMI_TX_REG_EXT_FS_RCAL_SHIFT 27
79#define UTMI_TX_REG_EXT_FS_RCAL_MASK (0xf << 27)
80
81#define UTMI_TX_REG_EXT_FS_RCAL_EN_SHIFT 26
82#define UTMI_TX_REG_EXT_FS_RCAL_EN_MASK (0x1 << 26)
83
84#define UTMI_TX_TXVDD12_SHIFT 22
85#define UTMI_TX_TXVDD12_MASK (0x3 << 22)
86
87#define UTMI_TX_CK60_PHSEL_SHIFT 17
88#define UTMI_TX_CK60_PHSEL_MASK (0xf << 17)
89
90#define UTMI_TX_IMPCAL_VTH_SHIFT 14
91#define UTMI_TX_IMPCAL_VTH_MASK (0x7 << 14)
92
93#define REG_RCAL_START (0x1 << 12)
94
95#define UTMI_TX_LOW_VDD_EN_SHIFT 11
96
97#define UTMI_TX_AMP_SHIFT 0
98#define UTMI_TX_AMP_MASK (0x7 << 0)
99
100/* For UTMI_RX Register */
101#define UTMI_REG_SQ_LENGTH_SHIFT 15
102#define UTMI_REG_SQ_LENGTH_MASK (0x3 << 15)
103
104#define UTMI_RX_SQ_THRESH_SHIFT 4
105#define UTMI_RX_SQ_THRESH_MASK (0xf << 4)
106
107#define UTMI_OTG_ADDON_OTG_ON (1 << 0)
108
109enum pxa_usb_phy_version {
110 PXA_USB_PHY_MMP2,
111 PXA_USB_PHY_PXA910,
112 PXA_USB_PHY_PXA168,
113};
114
115struct pxa_usb_phy {
116 struct phy *phy;
117 void __iomem *base;
118 enum pxa_usb_phy_version version;
119};
120
121/*****************************************************************************
122 * The registers read/write routines
123 *****************************************************************************/
124
125static unsigned int u2o_get(void __iomem *base, unsigned int offset)
126{
127 return readl_relaxed(base + offset);
128}
129
130static void u2o_set(void __iomem *base, unsigned int offset,
131 unsigned int value)
132{
133 u32 reg;
134
135 reg = readl_relaxed(base + offset);
136 reg |= value;
137 writel_relaxed(reg, base + offset);
138 readl_relaxed(base + offset);
139}
140
141static void u2o_clear(void __iomem *base, unsigned int offset,
142 unsigned int value)
143{
144 u32 reg;
145
146 reg = readl_relaxed(base + offset);
147 reg &= ~value;
148 writel_relaxed(reg, base + offset);
149 readl_relaxed(base + offset);
150}
151
152static void u2o_write(void __iomem *base, unsigned int offset,
153 unsigned int value)
154{
155 writel_relaxed(value, base + offset);
156 readl_relaxed(base + offset);
157}
158
159static int pxa_usb_phy_init(struct phy *phy)
160{
161 struct pxa_usb_phy *pxa_usb_phy = phy_get_drvdata(phy);
162 void __iomem *base = pxa_usb_phy->base;
163 int loops;
164
165 dev_info(&phy->dev, "initializing Marvell PXA USB PHY");
166
167 /* Initialize the USB PHY power */
168 if (pxa_usb_phy->version == PXA_USB_PHY_PXA910) {
169 u2o_set(base, UTMI_CTRL, (1<<UTMI_CTRL_INPKT_DELAY_SOF_SHIFT)
170 | (1<<UTMI_CTRL_PU_REF_SHIFT));
171 }
172
173 u2o_set(base, UTMI_CTRL, 1<<UTMI_CTRL_PLL_PWR_UP_SHIFT);
174 u2o_set(base, UTMI_CTRL, 1<<UTMI_CTRL_PWR_UP_SHIFT);
175
176 /* UTMI_PLL settings */
177 u2o_clear(base, UTMI_PLL, UTMI_PLL_PLLVDD18_MASK
178 | UTMI_PLL_PLLVDD12_MASK | UTMI_PLL_PLLCALI12_MASK
179 | UTMI_PLL_FBDIV_MASK | UTMI_PLL_REFDIV_MASK
180 | UTMI_PLL_ICP_MASK | UTMI_PLL_KVCO_MASK);
181
182 u2o_set(base, UTMI_PLL, 0xee<<UTMI_PLL_FBDIV_SHIFT
183 | 0xb<<UTMI_PLL_REFDIV_SHIFT | 3<<UTMI_PLL_PLLVDD18_SHIFT
184 | 3<<UTMI_PLL_PLLVDD12_SHIFT | 3<<UTMI_PLL_PLLCALI12_SHIFT
185 | 1<<UTMI_PLL_ICP_SHIFT | 3<<UTMI_PLL_KVCO_SHIFT);
186
187 /* UTMI_TX */
188 u2o_clear(base, UTMI_TX, UTMI_TX_REG_EXT_FS_RCAL_EN_MASK
189 | UTMI_TX_TXVDD12_MASK | UTMI_TX_CK60_PHSEL_MASK
190 | UTMI_TX_IMPCAL_VTH_MASK | UTMI_TX_REG_EXT_FS_RCAL_MASK
191 | UTMI_TX_AMP_MASK);
192 u2o_set(base, UTMI_TX, 3<<UTMI_TX_TXVDD12_SHIFT
193 | 4<<UTMI_TX_CK60_PHSEL_SHIFT | 4<<UTMI_TX_IMPCAL_VTH_SHIFT
194 | 8<<UTMI_TX_REG_EXT_FS_RCAL_SHIFT | 3<<UTMI_TX_AMP_SHIFT);
195
196 /* UTMI_RX */
197 u2o_clear(base, UTMI_RX, UTMI_RX_SQ_THRESH_MASK
198 | UTMI_REG_SQ_LENGTH_MASK);
199 u2o_set(base, UTMI_RX, 7<<UTMI_RX_SQ_THRESH_SHIFT
200 | 2<<UTMI_REG_SQ_LENGTH_SHIFT);
201
202 /* UTMI_IVREF */
203 if (pxa_usb_phy->version == PXA_USB_PHY_PXA168) {
204 /*
205 * fixing Microsoft Altair board interface with NEC hub issue -
206 * Set UTMI_IVREF from 0x4a3 to 0x4bf
207 */
208 u2o_write(base, UTMI_IVREF, 0x4bf);
209 }
210
211 /* toggle VCOCAL_START bit of UTMI_PLL */
212 udelay(200);
213 u2o_set(base, UTMI_PLL, VCOCAL_START);
214 udelay(40);
215 u2o_clear(base, UTMI_PLL, VCOCAL_START);
216
217 /* toggle REG_RCAL_START bit of UTMI_TX */
218 udelay(400);
219 u2o_set(base, UTMI_TX, REG_RCAL_START);
220 udelay(40);
221 u2o_clear(base, UTMI_TX, REG_RCAL_START);
222 udelay(400);
223
224 /* Make sure PHY PLL is ready */
225 loops = 0;
226 while ((u2o_get(base, UTMI_PLL) & PLL_READY) == 0) {
227 mdelay(1);
228 loops++;
229 if (loops > 100) {
230 dev_warn(&phy->dev, "calibrate timeout, UTMI_PLL %x\n",
231 u2o_get(base, UTMI_PLL));
232 break;
233 }
234 }
235
236 if (pxa_usb_phy->version == PXA_USB_PHY_PXA168) {
237 u2o_set(base, UTMI_RESERVE, 1 << 5);
238 /* Turn on UTMI PHY OTG extension */
239 u2o_write(base, UTMI_OTG_ADDON, 1);
240 }
241
242 return 0;
243
244}
245
246static int pxa_usb_phy_exit(struct phy *phy)
247{
248 struct pxa_usb_phy *pxa_usb_phy = phy_get_drvdata(phy);
249 void __iomem *base = pxa_usb_phy->base;
250
251 dev_info(&phy->dev, "deinitializing Marvell PXA USB PHY");
252
253 if (pxa_usb_phy->version == PXA_USB_PHY_PXA168)
254 u2o_clear(base, UTMI_OTG_ADDON, UTMI_OTG_ADDON_OTG_ON);
255
256 u2o_clear(base, UTMI_CTRL, UTMI_CTRL_RXBUF_PDWN);
257 u2o_clear(base, UTMI_CTRL, UTMI_CTRL_TXBUF_PDWN);
258 u2o_clear(base, UTMI_CTRL, UTMI_CTRL_USB_CLK_EN);
259 u2o_clear(base, UTMI_CTRL, 1<<UTMI_CTRL_PWR_UP_SHIFT);
260 u2o_clear(base, UTMI_CTRL, 1<<UTMI_CTRL_PLL_PWR_UP_SHIFT);
261
262 return 0;
263}
264
265static const struct phy_ops pxa_usb_phy_ops = {
266 .init = pxa_usb_phy_init,
267 .exit = pxa_usb_phy_exit,
268 .owner = THIS_MODULE,
269};
270
271static const struct of_device_id pxa_usb_phy_of_match[] = {
272 {
273 .compatible = "marvell,mmp2-usb-phy",
274 .data = (void *)PXA_USB_PHY_MMP2,
275 }, {
276 .compatible = "marvell,pxa910-usb-phy",
277 .data = (void *)PXA_USB_PHY_PXA910,
278 }, {
279 .compatible = "marvell,pxa168-usb-phy",
280 .data = (void *)PXA_USB_PHY_PXA168,
281 },
282 { },
283};
284MODULE_DEVICE_TABLE(of, pxa_usb_phy_of_match);
285
286static int pxa_usb_phy_probe(struct platform_device *pdev)
287{
288 struct device *dev = &pdev->dev;
289 struct resource *resource;
290 struct pxa_usb_phy *pxa_usb_phy;
291 struct phy_provider *provider;
292 const struct of_device_id *of_id;
293
294 pxa_usb_phy = devm_kzalloc(dev, sizeof(struct pxa_usb_phy), GFP_KERNEL);
295 if (!pxa_usb_phy)
296 return -ENOMEM;
297
298 of_id = of_match_node(pxa_usb_phy_of_match, dev->of_node);
299 if (of_id)
300 pxa_usb_phy->version = (enum pxa_usb_phy_version)of_id->data;
301 else
302 pxa_usb_phy->version = PXA_USB_PHY_MMP2;
303
304 resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
305 pxa_usb_phy->base = devm_ioremap_resource(dev, resource);
306 if (IS_ERR(pxa_usb_phy->base)) {
307 dev_err(dev, "failed to remap PHY regs\n");
308 return PTR_ERR(pxa_usb_phy->base);
309 }
310
311 pxa_usb_phy->phy = devm_phy_create(dev, NULL, &pxa_usb_phy_ops);
312 if (IS_ERR(pxa_usb_phy->phy)) {
313 dev_err(dev, "failed to create PHY\n");
314 return PTR_ERR(pxa_usb_phy->phy);
315 }
316
317 phy_set_drvdata(pxa_usb_phy->phy, pxa_usb_phy);
318 provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
319 if (IS_ERR(provider)) {
320 dev_err(dev, "failed to register PHY provider\n");
321 return PTR_ERR(provider);
322 }
323
324 if (!dev->of_node) {
325 phy_create_lookup(pxa_usb_phy->phy, "usb", "mv-udc");
326 phy_create_lookup(pxa_usb_phy->phy, "usb", "pxa-u2oehci");
327 phy_create_lookup(pxa_usb_phy->phy, "usb", "mv-otg");
328 }
329
330 dev_info(dev, "Marvell PXA USB PHY");
331 return 0;
332}
333
334static struct platform_driver pxa_usb_phy_driver = {
335 .probe = pxa_usb_phy_probe,
336 .driver = {
337 .name = "pxa-usb-phy",
338 .of_match_table = pxa_usb_phy_of_match,
339 },
340};
341module_platform_driver(pxa_usb_phy_driver);
342
343MODULE_AUTHOR("Lubomir Rintel <lkundrak@v3.sk>");
344MODULE_DESCRIPTION("Marvell PXA USB PHY Driver");
345MODULE_LICENSE("GPL v2");