Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright 2012 Freescale Semiconductor, Inc.
4 */
5
6#include <linux/module.h>
7#include <linux/of_platform.h>
8#include <linux/err.h>
9#include <linux/io.h>
10#include <linux/delay.h>
11
12#include "ci_hdrc_imx.h"
13
14#define MX25_USB_PHY_CTRL_OFFSET 0x08
15#define MX25_BM_EXTERNAL_VBUS_DIVIDER BIT(23)
16
17#define MX25_EHCI_INTERFACE_SINGLE_UNI (2 << 0)
18#define MX25_EHCI_INTERFACE_DIFF_UNI (0 << 0)
19#define MX25_EHCI_INTERFACE_MASK (0xf)
20
21#define MX25_OTG_SIC_SHIFT 29
22#define MX25_OTG_SIC_MASK (0x3 << MX25_OTG_SIC_SHIFT)
23#define MX25_OTG_PM_BIT BIT(24)
24#define MX25_OTG_PP_BIT BIT(11)
25#define MX25_OTG_OCPOL_BIT BIT(3)
26
27#define MX25_H1_SIC_SHIFT 21
28#define MX25_H1_SIC_MASK (0x3 << MX25_H1_SIC_SHIFT)
29#define MX25_H1_PP_BIT BIT(18)
30#define MX25_H1_PM_BIT BIT(16)
31#define MX25_H1_IPPUE_UP_BIT BIT(7)
32#define MX25_H1_IPPUE_DOWN_BIT BIT(6)
33#define MX25_H1_TLL_BIT BIT(5)
34#define MX25_H1_USBTE_BIT BIT(4)
35#define MX25_H1_OCPOL_BIT BIT(2)
36
37#define MX27_H1_PM_BIT BIT(8)
38#define MX27_H2_PM_BIT BIT(16)
39#define MX27_OTG_PM_BIT BIT(24)
40
41#define MX53_USB_OTG_PHY_CTRL_0_OFFSET 0x08
42#define MX53_USB_OTG_PHY_CTRL_1_OFFSET 0x0c
43#define MX53_USB_CTRL_1_OFFSET 0x10
44#define MX53_USB_CTRL_1_H2_XCVR_CLK_SEL_MASK (0x11 << 2)
45#define MX53_USB_CTRL_1_H2_XCVR_CLK_SEL_ULPI BIT(2)
46#define MX53_USB_CTRL_1_H3_XCVR_CLK_SEL_MASK (0x11 << 6)
47#define MX53_USB_CTRL_1_H3_XCVR_CLK_SEL_ULPI BIT(6)
48#define MX53_USB_UH2_CTRL_OFFSET 0x14
49#define MX53_USB_UH3_CTRL_OFFSET 0x18
50#define MX53_USB_CLKONOFF_CTRL_OFFSET 0x24
51#define MX53_USB_CLKONOFF_CTRL_H2_INT60CKOFF BIT(21)
52#define MX53_USB_CLKONOFF_CTRL_H3_INT60CKOFF BIT(22)
53#define MX53_BM_OVER_CUR_DIS_H1 BIT(5)
54#define MX53_BM_OVER_CUR_DIS_OTG BIT(8)
55#define MX53_BM_OVER_CUR_DIS_UHx BIT(30)
56#define MX53_USB_CTRL_1_UH2_ULPI_EN BIT(26)
57#define MX53_USB_CTRL_1_UH3_ULPI_EN BIT(27)
58#define MX53_USB_UHx_CTRL_WAKE_UP_EN BIT(7)
59#define MX53_USB_UHx_CTRL_ULPI_INT_EN BIT(8)
60#define MX53_USB_PHYCTRL1_PLLDIV_MASK 0x3
61#define MX53_USB_PLL_DIV_24_MHZ 0x01
62
63#define MX6_BM_NON_BURST_SETTING BIT(1)
64#define MX6_BM_OVER_CUR_DIS BIT(7)
65#define MX6_BM_OVER_CUR_POLARITY BIT(8)
66#define MX6_BM_WAKEUP_ENABLE BIT(10)
67#define MX6_BM_UTMI_ON_CLOCK BIT(13)
68#define MX6_BM_ID_WAKEUP BIT(16)
69#define MX6_BM_VBUS_WAKEUP BIT(17)
70#define MX6SX_BM_DPDM_WAKEUP_EN BIT(29)
71#define MX6_BM_WAKEUP_INTR BIT(31)
72
73#define MX6_USB_HSIC_CTRL_OFFSET 0x10
74/* Send resume signal without 480Mhz PHY clock */
75#define MX6SX_BM_HSIC_AUTO_RESUME BIT(23)
76/* set before portsc.suspendM = 1 */
77#define MX6_BM_HSIC_DEV_CONN BIT(21)
78/* HSIC enable */
79#define MX6_BM_HSIC_EN BIT(12)
80/* Force HSIC module 480M clock on, even when in Host is in suspend mode */
81#define MX6_BM_HSIC_CLK_ON BIT(11)
82
83#define MX6_USB_OTG1_PHY_CTRL 0x18
84/* For imx6dql, it is host-only controller, for later imx6, it is otg's */
85#define MX6_USB_OTG2_PHY_CTRL 0x1c
86#define MX6SX_USB_VBUS_WAKEUP_SOURCE(v) (v << 8)
87#define MX6SX_USB_VBUS_WAKEUP_SOURCE_VBUS MX6SX_USB_VBUS_WAKEUP_SOURCE(0)
88#define MX6SX_USB_VBUS_WAKEUP_SOURCE_AVALID MX6SX_USB_VBUS_WAKEUP_SOURCE(1)
89#define MX6SX_USB_VBUS_WAKEUP_SOURCE_BVALID MX6SX_USB_VBUS_WAKEUP_SOURCE(2)
90#define MX6SX_USB_VBUS_WAKEUP_SOURCE_SESS_END MX6SX_USB_VBUS_WAKEUP_SOURCE(3)
91
92#define VF610_OVER_CUR_DIS BIT(7)
93
94#define MX7D_USBNC_USB_CTRL2 0x4
95#define MX7D_USB_VBUS_WAKEUP_SOURCE_MASK 0x3
96#define MX7D_USB_VBUS_WAKEUP_SOURCE(v) (v << 0)
97#define MX7D_USB_VBUS_WAKEUP_SOURCE_VBUS MX7D_USB_VBUS_WAKEUP_SOURCE(0)
98#define MX7D_USB_VBUS_WAKEUP_SOURCE_AVALID MX7D_USB_VBUS_WAKEUP_SOURCE(1)
99#define MX7D_USB_VBUS_WAKEUP_SOURCE_BVALID MX7D_USB_VBUS_WAKEUP_SOURCE(2)
100#define MX7D_USB_VBUS_WAKEUP_SOURCE_SESS_END MX7D_USB_VBUS_WAKEUP_SOURCE(3)
101
102struct usbmisc_ops {
103 /* It's called once when probe a usb device */
104 int (*init)(struct imx_usbmisc_data *data);
105 /* It's called once after adding a usb device */
106 int (*post)(struct imx_usbmisc_data *data);
107 /* It's called when we need to enable/disable usb wakeup */
108 int (*set_wakeup)(struct imx_usbmisc_data *data, bool enabled);
109 /* It's called before setting portsc.suspendM */
110 int (*hsic_set_connect)(struct imx_usbmisc_data *data);
111 /* It's called during suspend/resume */
112 int (*hsic_set_clk)(struct imx_usbmisc_data *data, bool enabled);
113};
114
115struct imx_usbmisc {
116 void __iomem *base;
117 spinlock_t lock;
118 const struct usbmisc_ops *ops;
119};
120
121static inline bool is_imx53_usbmisc(struct imx_usbmisc_data *data);
122
123static int usbmisc_imx25_init(struct imx_usbmisc_data *data)
124{
125 struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev);
126 unsigned long flags;
127 u32 val = 0;
128
129 if (data->index > 1)
130 return -EINVAL;
131
132 spin_lock_irqsave(&usbmisc->lock, flags);
133 switch (data->index) {
134 case 0:
135 val = readl(usbmisc->base);
136 val &= ~(MX25_OTG_SIC_MASK | MX25_OTG_PP_BIT);
137 val |= (MX25_EHCI_INTERFACE_DIFF_UNI & MX25_EHCI_INTERFACE_MASK) << MX25_OTG_SIC_SHIFT;
138 val |= (MX25_OTG_PM_BIT | MX25_OTG_OCPOL_BIT);
139
140 /*
141 * If the polarity is not configured assume active high for
142 * historical reasons.
143 */
144 if (data->oc_pol_configured && data->oc_pol_active_low)
145 val &= ~MX25_OTG_OCPOL_BIT;
146
147 writel(val, usbmisc->base);
148 break;
149 case 1:
150 val = readl(usbmisc->base);
151 val &= ~(MX25_H1_SIC_MASK | MX25_H1_PP_BIT | MX25_H1_IPPUE_UP_BIT);
152 val |= (MX25_EHCI_INTERFACE_SINGLE_UNI & MX25_EHCI_INTERFACE_MASK) << MX25_H1_SIC_SHIFT;
153 val |= (MX25_H1_PM_BIT | MX25_H1_OCPOL_BIT | MX25_H1_TLL_BIT |
154 MX25_H1_USBTE_BIT | MX25_H1_IPPUE_DOWN_BIT);
155
156 /*
157 * If the polarity is not configured assume active high for
158 * historical reasons.
159 */
160 if (data->oc_pol_configured && data->oc_pol_active_low)
161 val &= ~MX25_H1_OCPOL_BIT;
162
163 writel(val, usbmisc->base);
164
165 break;
166 }
167 spin_unlock_irqrestore(&usbmisc->lock, flags);
168
169 return 0;
170}
171
172static int usbmisc_imx25_post(struct imx_usbmisc_data *data)
173{
174 struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev);
175 void __iomem *reg;
176 unsigned long flags;
177 u32 val;
178
179 if (data->index > 2)
180 return -EINVAL;
181
182 if (data->index)
183 return 0;
184
185 spin_lock_irqsave(&usbmisc->lock, flags);
186 reg = usbmisc->base + MX25_USB_PHY_CTRL_OFFSET;
187 val = readl(reg);
188
189 if (data->evdo)
190 val |= MX25_BM_EXTERNAL_VBUS_DIVIDER;
191 else
192 val &= ~MX25_BM_EXTERNAL_VBUS_DIVIDER;
193
194 writel(val, reg);
195 spin_unlock_irqrestore(&usbmisc->lock, flags);
196 usleep_range(5000, 10000); /* needed to stabilize voltage */
197
198 return 0;
199}
200
201static int usbmisc_imx27_init(struct imx_usbmisc_data *data)
202{
203 struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev);
204 unsigned long flags;
205 u32 val;
206
207 switch (data->index) {
208 case 0:
209 val = MX27_OTG_PM_BIT;
210 break;
211 case 1:
212 val = MX27_H1_PM_BIT;
213 break;
214 case 2:
215 val = MX27_H2_PM_BIT;
216 break;
217 default:
218 return -EINVAL;
219 }
220
221 spin_lock_irqsave(&usbmisc->lock, flags);
222 if (data->disable_oc)
223 val = readl(usbmisc->base) | val;
224 else
225 val = readl(usbmisc->base) & ~val;
226 writel(val, usbmisc->base);
227 spin_unlock_irqrestore(&usbmisc->lock, flags);
228
229 return 0;
230}
231
232static int usbmisc_imx53_init(struct imx_usbmisc_data *data)
233{
234 struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev);
235 void __iomem *reg = NULL;
236 unsigned long flags;
237 u32 val = 0;
238
239 if (data->index > 3)
240 return -EINVAL;
241
242 /* Select a 24 MHz reference clock for the PHY */
243 val = readl(usbmisc->base + MX53_USB_OTG_PHY_CTRL_1_OFFSET);
244 val &= ~MX53_USB_PHYCTRL1_PLLDIV_MASK;
245 val |= MX53_USB_PLL_DIV_24_MHZ;
246 writel(val, usbmisc->base + MX53_USB_OTG_PHY_CTRL_1_OFFSET);
247
248 spin_lock_irqsave(&usbmisc->lock, flags);
249
250 switch (data->index) {
251 case 0:
252 if (data->disable_oc) {
253 reg = usbmisc->base + MX53_USB_OTG_PHY_CTRL_0_OFFSET;
254 val = readl(reg) | MX53_BM_OVER_CUR_DIS_OTG;
255 writel(val, reg);
256 }
257 break;
258 case 1:
259 if (data->disable_oc) {
260 reg = usbmisc->base + MX53_USB_OTG_PHY_CTRL_0_OFFSET;
261 val = readl(reg) | MX53_BM_OVER_CUR_DIS_H1;
262 writel(val, reg);
263 }
264 break;
265 case 2:
266 if (data->ulpi) {
267 /* set USBH2 into ULPI-mode. */
268 reg = usbmisc->base + MX53_USB_CTRL_1_OFFSET;
269 val = readl(reg) | MX53_USB_CTRL_1_UH2_ULPI_EN;
270 /* select ULPI clock */
271 val &= ~MX53_USB_CTRL_1_H2_XCVR_CLK_SEL_MASK;
272 val |= MX53_USB_CTRL_1_H2_XCVR_CLK_SEL_ULPI;
273 writel(val, reg);
274 /* Set interrupt wake up enable */
275 reg = usbmisc->base + MX53_USB_UH2_CTRL_OFFSET;
276 val = readl(reg) | MX53_USB_UHx_CTRL_WAKE_UP_EN
277 | MX53_USB_UHx_CTRL_ULPI_INT_EN;
278 writel(val, reg);
279 if (is_imx53_usbmisc(data)) {
280 /* Disable internal 60Mhz clock */
281 reg = usbmisc->base +
282 MX53_USB_CLKONOFF_CTRL_OFFSET;
283 val = readl(reg) |
284 MX53_USB_CLKONOFF_CTRL_H2_INT60CKOFF;
285 writel(val, reg);
286 }
287
288 }
289 if (data->disable_oc) {
290 reg = usbmisc->base + MX53_USB_UH2_CTRL_OFFSET;
291 val = readl(reg) | MX53_BM_OVER_CUR_DIS_UHx;
292 writel(val, reg);
293 }
294 break;
295 case 3:
296 if (data->ulpi) {
297 /* set USBH3 into ULPI-mode. */
298 reg = usbmisc->base + MX53_USB_CTRL_1_OFFSET;
299 val = readl(reg) | MX53_USB_CTRL_1_UH3_ULPI_EN;
300 /* select ULPI clock */
301 val &= ~MX53_USB_CTRL_1_H3_XCVR_CLK_SEL_MASK;
302 val |= MX53_USB_CTRL_1_H3_XCVR_CLK_SEL_ULPI;
303 writel(val, reg);
304 /* Set interrupt wake up enable */
305 reg = usbmisc->base + MX53_USB_UH3_CTRL_OFFSET;
306 val = readl(reg) | MX53_USB_UHx_CTRL_WAKE_UP_EN
307 | MX53_USB_UHx_CTRL_ULPI_INT_EN;
308 writel(val, reg);
309
310 if (is_imx53_usbmisc(data)) {
311 /* Disable internal 60Mhz clock */
312 reg = usbmisc->base +
313 MX53_USB_CLKONOFF_CTRL_OFFSET;
314 val = readl(reg) |
315 MX53_USB_CLKONOFF_CTRL_H3_INT60CKOFF;
316 writel(val, reg);
317 }
318 }
319 if (data->disable_oc) {
320 reg = usbmisc->base + MX53_USB_UH3_CTRL_OFFSET;
321 val = readl(reg) | MX53_BM_OVER_CUR_DIS_UHx;
322 writel(val, reg);
323 }
324 break;
325 }
326
327 spin_unlock_irqrestore(&usbmisc->lock, flags);
328
329 return 0;
330}
331
332static int usbmisc_imx6q_set_wakeup
333 (struct imx_usbmisc_data *data, bool enabled)
334{
335 struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev);
336 unsigned long flags;
337 u32 val;
338 u32 wakeup_setting = (MX6_BM_WAKEUP_ENABLE |
339 MX6_BM_VBUS_WAKEUP | MX6_BM_ID_WAKEUP);
340 int ret = 0;
341
342 if (data->index > 3)
343 return -EINVAL;
344
345 spin_lock_irqsave(&usbmisc->lock, flags);
346 val = readl(usbmisc->base + data->index * 4);
347 if (enabled) {
348 val |= wakeup_setting;
349 } else {
350 if (val & MX6_BM_WAKEUP_INTR)
351 pr_debug("wakeup int at ci_hdrc.%d\n", data->index);
352 val &= ~wakeup_setting;
353 }
354 writel(val, usbmisc->base + data->index * 4);
355 spin_unlock_irqrestore(&usbmisc->lock, flags);
356
357 return ret;
358}
359
360static int usbmisc_imx6q_init(struct imx_usbmisc_data *data)
361{
362 struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev);
363 unsigned long flags;
364 u32 reg;
365
366 if (data->index > 3)
367 return -EINVAL;
368
369 spin_lock_irqsave(&usbmisc->lock, flags);
370
371 reg = readl(usbmisc->base + data->index * 4);
372 if (data->disable_oc) {
373 reg |= MX6_BM_OVER_CUR_DIS;
374 } else {
375 reg &= ~MX6_BM_OVER_CUR_DIS;
376
377 /*
378 * If the polarity is not configured keep it as setup by the
379 * bootloader.
380 */
381 if (data->oc_pol_configured && data->oc_pol_active_low)
382 reg |= MX6_BM_OVER_CUR_POLARITY;
383 else if (data->oc_pol_configured)
384 reg &= ~MX6_BM_OVER_CUR_POLARITY;
385 }
386 writel(reg, usbmisc->base + data->index * 4);
387
388 /* SoC non-burst setting */
389 reg = readl(usbmisc->base + data->index * 4);
390 writel(reg | MX6_BM_NON_BURST_SETTING,
391 usbmisc->base + data->index * 4);
392
393 /* For HSIC controller */
394 if (data->hsic) {
395 reg = readl(usbmisc->base + data->index * 4);
396 writel(reg | MX6_BM_UTMI_ON_CLOCK,
397 usbmisc->base + data->index * 4);
398 reg = readl(usbmisc->base + MX6_USB_HSIC_CTRL_OFFSET
399 + (data->index - 2) * 4);
400 reg |= MX6_BM_HSIC_EN | MX6_BM_HSIC_CLK_ON;
401 writel(reg, usbmisc->base + MX6_USB_HSIC_CTRL_OFFSET
402 + (data->index - 2) * 4);
403 }
404
405 spin_unlock_irqrestore(&usbmisc->lock, flags);
406
407 usbmisc_imx6q_set_wakeup(data, false);
408
409 return 0;
410}
411
412static int usbmisc_imx6_hsic_get_reg_offset(struct imx_usbmisc_data *data)
413{
414 int offset, ret = 0;
415
416 if (data->index == 2 || data->index == 3) {
417 offset = (data->index - 2) * 4;
418 } else if (data->index == 0) {
419 /*
420 * For SoCs like i.MX7D and later, each USB controller has
421 * its own non-core register region. For SoCs before i.MX7D,
422 * the first two USB controllers are non-HSIC controllers.
423 */
424 offset = 0;
425 } else {
426 dev_err(data->dev, "index is error for usbmisc\n");
427 ret = -EINVAL;
428 }
429
430 return ret ? ret : offset;
431}
432
433static int usbmisc_imx6_hsic_set_connect(struct imx_usbmisc_data *data)
434{
435 unsigned long flags;
436 u32 val;
437 struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev);
438 int offset;
439
440 spin_lock_irqsave(&usbmisc->lock, flags);
441 offset = usbmisc_imx6_hsic_get_reg_offset(data);
442 if (offset < 0) {
443 spin_unlock_irqrestore(&usbmisc->lock, flags);
444 return offset;
445 }
446
447 val = readl(usbmisc->base + MX6_USB_HSIC_CTRL_OFFSET + offset);
448 if (!(val & MX6_BM_HSIC_DEV_CONN))
449 writel(val | MX6_BM_HSIC_DEV_CONN,
450 usbmisc->base + MX6_USB_HSIC_CTRL_OFFSET + offset);
451
452 spin_unlock_irqrestore(&usbmisc->lock, flags);
453
454 return 0;
455}
456
457static int usbmisc_imx6_hsic_set_clk(struct imx_usbmisc_data *data, bool on)
458{
459 unsigned long flags;
460 u32 val;
461 struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev);
462 int offset;
463
464 spin_lock_irqsave(&usbmisc->lock, flags);
465 offset = usbmisc_imx6_hsic_get_reg_offset(data);
466 if (offset < 0) {
467 spin_unlock_irqrestore(&usbmisc->lock, flags);
468 return offset;
469 }
470
471 val = readl(usbmisc->base + MX6_USB_HSIC_CTRL_OFFSET + offset);
472 val |= MX6_BM_HSIC_EN | MX6_BM_HSIC_CLK_ON;
473 if (on)
474 val |= MX6_BM_HSIC_CLK_ON;
475 else
476 val &= ~MX6_BM_HSIC_CLK_ON;
477
478 writel(val, usbmisc->base + MX6_USB_HSIC_CTRL_OFFSET + offset);
479 spin_unlock_irqrestore(&usbmisc->lock, flags);
480
481 return 0;
482}
483
484
485static int usbmisc_imx6sx_init(struct imx_usbmisc_data *data)
486{
487 void __iomem *reg = NULL;
488 unsigned long flags;
489 struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev);
490 u32 val;
491
492 usbmisc_imx6q_init(data);
493
494 if (data->index == 0 || data->index == 1) {
495 reg = usbmisc->base + MX6_USB_OTG1_PHY_CTRL + data->index * 4;
496 spin_lock_irqsave(&usbmisc->lock, flags);
497 /* Set vbus wakeup source as bvalid */
498 val = readl(reg);
499 writel(val | MX6SX_USB_VBUS_WAKEUP_SOURCE_BVALID, reg);
500 /*
501 * Disable dp/dm wakeup in device mode when vbus is
502 * not there.
503 */
504 val = readl(usbmisc->base + data->index * 4);
505 writel(val & ~MX6SX_BM_DPDM_WAKEUP_EN,
506 usbmisc->base + data->index * 4);
507 spin_unlock_irqrestore(&usbmisc->lock, flags);
508 }
509
510 /* For HSIC controller */
511 if (data->hsic) {
512 val = readl(usbmisc->base + MX6_USB_HSIC_CTRL_OFFSET);
513 val |= MX6SX_BM_HSIC_AUTO_RESUME;
514 writel(val, usbmisc->base + MX6_USB_HSIC_CTRL_OFFSET);
515 }
516
517 return 0;
518}
519
520static int usbmisc_vf610_init(struct imx_usbmisc_data *data)
521{
522 struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev);
523 u32 reg;
524
525 /*
526 * Vybrid only has one misc register set, but in two different
527 * areas. These is reflected in two instances of this driver.
528 */
529 if (data->index >= 1)
530 return -EINVAL;
531
532 if (data->disable_oc) {
533 reg = readl(usbmisc->base);
534 writel(reg | VF610_OVER_CUR_DIS, usbmisc->base);
535 }
536
537 return 0;
538}
539
540static int usbmisc_imx7d_set_wakeup
541 (struct imx_usbmisc_data *data, bool enabled)
542{
543 struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev);
544 unsigned long flags;
545 u32 val;
546 u32 wakeup_setting = (MX6_BM_WAKEUP_ENABLE |
547 MX6_BM_VBUS_WAKEUP | MX6_BM_ID_WAKEUP);
548
549 spin_lock_irqsave(&usbmisc->lock, flags);
550 val = readl(usbmisc->base);
551 if (enabled) {
552 writel(val | wakeup_setting, usbmisc->base);
553 } else {
554 if (val & MX6_BM_WAKEUP_INTR)
555 dev_dbg(data->dev, "wakeup int\n");
556 writel(val & ~wakeup_setting, usbmisc->base);
557 }
558 spin_unlock_irqrestore(&usbmisc->lock, flags);
559
560 return 0;
561}
562
563static int usbmisc_imx7d_init(struct imx_usbmisc_data *data)
564{
565 struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev);
566 unsigned long flags;
567 u32 reg;
568
569 if (data->index >= 1)
570 return -EINVAL;
571
572 spin_lock_irqsave(&usbmisc->lock, flags);
573 reg = readl(usbmisc->base);
574 if (data->disable_oc) {
575 reg |= MX6_BM_OVER_CUR_DIS;
576 } else {
577 reg &= ~MX6_BM_OVER_CUR_DIS;
578
579 /*
580 * If the polarity is not configured keep it as setup by the
581 * bootloader.
582 */
583 if (data->oc_pol_configured && data->oc_pol_active_low)
584 reg |= MX6_BM_OVER_CUR_POLARITY;
585 else if (data->oc_pol_configured)
586 reg &= ~MX6_BM_OVER_CUR_POLARITY;
587 }
588 writel(reg, usbmisc->base);
589
590 reg = readl(usbmisc->base + MX7D_USBNC_USB_CTRL2);
591 reg &= ~MX7D_USB_VBUS_WAKEUP_SOURCE_MASK;
592 writel(reg | MX7D_USB_VBUS_WAKEUP_SOURCE_BVALID,
593 usbmisc->base + MX7D_USBNC_USB_CTRL2);
594
595 spin_unlock_irqrestore(&usbmisc->lock, flags);
596
597 usbmisc_imx7d_set_wakeup(data, false);
598
599 return 0;
600}
601
602static const struct usbmisc_ops imx25_usbmisc_ops = {
603 .init = usbmisc_imx25_init,
604 .post = usbmisc_imx25_post,
605};
606
607static const struct usbmisc_ops imx27_usbmisc_ops = {
608 .init = usbmisc_imx27_init,
609};
610
611static const struct usbmisc_ops imx51_usbmisc_ops = {
612 .init = usbmisc_imx53_init,
613};
614
615static const struct usbmisc_ops imx53_usbmisc_ops = {
616 .init = usbmisc_imx53_init,
617};
618
619static const struct usbmisc_ops imx6q_usbmisc_ops = {
620 .set_wakeup = usbmisc_imx6q_set_wakeup,
621 .init = usbmisc_imx6q_init,
622 .hsic_set_connect = usbmisc_imx6_hsic_set_connect,
623 .hsic_set_clk = usbmisc_imx6_hsic_set_clk,
624};
625
626static const struct usbmisc_ops vf610_usbmisc_ops = {
627 .init = usbmisc_vf610_init,
628};
629
630static const struct usbmisc_ops imx6sx_usbmisc_ops = {
631 .set_wakeup = usbmisc_imx6q_set_wakeup,
632 .init = usbmisc_imx6sx_init,
633 .hsic_set_connect = usbmisc_imx6_hsic_set_connect,
634 .hsic_set_clk = usbmisc_imx6_hsic_set_clk,
635};
636
637static const struct usbmisc_ops imx7d_usbmisc_ops = {
638 .init = usbmisc_imx7d_init,
639 .set_wakeup = usbmisc_imx7d_set_wakeup,
640};
641
642static inline bool is_imx53_usbmisc(struct imx_usbmisc_data *data)
643{
644 struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev);
645
646 return usbmisc->ops == &imx53_usbmisc_ops;
647}
648
649int imx_usbmisc_init(struct imx_usbmisc_data *data)
650{
651 struct imx_usbmisc *usbmisc;
652
653 if (!data)
654 return 0;
655
656 usbmisc = dev_get_drvdata(data->dev);
657 if (!usbmisc->ops->init)
658 return 0;
659 return usbmisc->ops->init(data);
660}
661EXPORT_SYMBOL_GPL(imx_usbmisc_init);
662
663int imx_usbmisc_init_post(struct imx_usbmisc_data *data)
664{
665 struct imx_usbmisc *usbmisc;
666
667 if (!data)
668 return 0;
669
670 usbmisc = dev_get_drvdata(data->dev);
671 if (!usbmisc->ops->post)
672 return 0;
673 return usbmisc->ops->post(data);
674}
675EXPORT_SYMBOL_GPL(imx_usbmisc_init_post);
676
677int imx_usbmisc_set_wakeup(struct imx_usbmisc_data *data, bool enabled)
678{
679 struct imx_usbmisc *usbmisc;
680
681 if (!data)
682 return 0;
683
684 usbmisc = dev_get_drvdata(data->dev);
685 if (!usbmisc->ops->set_wakeup)
686 return 0;
687 return usbmisc->ops->set_wakeup(data, enabled);
688}
689EXPORT_SYMBOL_GPL(imx_usbmisc_set_wakeup);
690
691int imx_usbmisc_hsic_set_connect(struct imx_usbmisc_data *data)
692{
693 struct imx_usbmisc *usbmisc;
694
695 if (!data)
696 return 0;
697
698 usbmisc = dev_get_drvdata(data->dev);
699 if (!usbmisc->ops->hsic_set_connect || !data->hsic)
700 return 0;
701 return usbmisc->ops->hsic_set_connect(data);
702}
703EXPORT_SYMBOL_GPL(imx_usbmisc_hsic_set_connect);
704
705int imx_usbmisc_hsic_set_clk(struct imx_usbmisc_data *data, bool on)
706{
707 struct imx_usbmisc *usbmisc;
708
709 if (!data)
710 return 0;
711
712 usbmisc = dev_get_drvdata(data->dev);
713 if (!usbmisc->ops->hsic_set_clk || !data->hsic)
714 return 0;
715 return usbmisc->ops->hsic_set_clk(data, on);
716}
717EXPORT_SYMBOL_GPL(imx_usbmisc_hsic_set_clk);
718static const struct of_device_id usbmisc_imx_dt_ids[] = {
719 {
720 .compatible = "fsl,imx25-usbmisc",
721 .data = &imx25_usbmisc_ops,
722 },
723 {
724 .compatible = "fsl,imx35-usbmisc",
725 .data = &imx25_usbmisc_ops,
726 },
727 {
728 .compatible = "fsl,imx27-usbmisc",
729 .data = &imx27_usbmisc_ops,
730 },
731 {
732 .compatible = "fsl,imx51-usbmisc",
733 .data = &imx51_usbmisc_ops,
734 },
735 {
736 .compatible = "fsl,imx53-usbmisc",
737 .data = &imx53_usbmisc_ops,
738 },
739 {
740 .compatible = "fsl,imx6q-usbmisc",
741 .data = &imx6q_usbmisc_ops,
742 },
743 {
744 .compatible = "fsl,vf610-usbmisc",
745 .data = &vf610_usbmisc_ops,
746 },
747 {
748 .compatible = "fsl,imx6sx-usbmisc",
749 .data = &imx6sx_usbmisc_ops,
750 },
751 {
752 .compatible = "fsl,imx6ul-usbmisc",
753 .data = &imx6sx_usbmisc_ops,
754 },
755 {
756 .compatible = "fsl,imx7d-usbmisc",
757 .data = &imx7d_usbmisc_ops,
758 },
759 { /* sentinel */ }
760};
761MODULE_DEVICE_TABLE(of, usbmisc_imx_dt_ids);
762
763static int usbmisc_imx_probe(struct platform_device *pdev)
764{
765 struct resource *res;
766 struct imx_usbmisc *data;
767 const struct of_device_id *of_id;
768
769 of_id = of_match_device(usbmisc_imx_dt_ids, &pdev->dev);
770 if (!of_id)
771 return -ENODEV;
772
773 data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
774 if (!data)
775 return -ENOMEM;
776
777 spin_lock_init(&data->lock);
778
779 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
780 data->base = devm_ioremap_resource(&pdev->dev, res);
781 if (IS_ERR(data->base))
782 return PTR_ERR(data->base);
783
784 data->ops = (const struct usbmisc_ops *)of_id->data;
785 platform_set_drvdata(pdev, data);
786
787 return 0;
788}
789
790static int usbmisc_imx_remove(struct platform_device *pdev)
791{
792 return 0;
793}
794
795static struct platform_driver usbmisc_imx_driver = {
796 .probe = usbmisc_imx_probe,
797 .remove = usbmisc_imx_remove,
798 .driver = {
799 .name = "usbmisc_imx",
800 .of_match_table = usbmisc_imx_dt_ids,
801 },
802};
803
804module_platform_driver(usbmisc_imx_driver);
805
806MODULE_ALIAS("platform:usbmisc-imx");
807MODULE_LICENSE("GPL");
808MODULE_DESCRIPTION("driver for imx usb non-core registers");
809MODULE_AUTHOR("Richard Zhao <richard.zhao@freescale.com>");