forked from ~ljy/RK356X_SDK_RELEASE

hc
2024-01-04 1543e317f1da31b75942316931e8f491a8920811
kernel/drivers/usb/chipidea/usbmisc_imx.c
....@@ -8,6 +8,7 @@
88 #include <linux/err.h>
99 #include <linux/io.h>
1010 #include <linux/delay.h>
11
+#include <linux/usb/otg.h>
1112
1213 #include "ci_hdrc_imx.h"
1314
....@@ -63,11 +64,24 @@
6364 #define MX6_BM_NON_BURST_SETTING BIT(1)
6465 #define MX6_BM_OVER_CUR_DIS BIT(7)
6566 #define MX6_BM_OVER_CUR_POLARITY BIT(8)
67
+#define MX6_BM_PWR_POLARITY BIT(9)
6668 #define MX6_BM_WAKEUP_ENABLE BIT(10)
69
+#define MX6_BM_UTMI_ON_CLOCK BIT(13)
6770 #define MX6_BM_ID_WAKEUP BIT(16)
6871 #define MX6_BM_VBUS_WAKEUP BIT(17)
6972 #define MX6SX_BM_DPDM_WAKEUP_EN BIT(29)
7073 #define MX6_BM_WAKEUP_INTR BIT(31)
74
+
75
+#define MX6_USB_HSIC_CTRL_OFFSET 0x10
76
+/* Send resume signal without 480Mhz PHY clock */
77
+#define MX6SX_BM_HSIC_AUTO_RESUME BIT(23)
78
+/* set before portsc.suspendM = 1 */
79
+#define MX6_BM_HSIC_DEV_CONN BIT(21)
80
+/* HSIC enable */
81
+#define MX6_BM_HSIC_EN BIT(12)
82
+/* Force HSIC module 480M clock on, even when in Host is in suspend mode */
83
+#define MX6_BM_HSIC_CLK_ON BIT(11)
84
+
7185 #define MX6_USB_OTG1_PHY_CTRL 0x18
7286 /* For imx6dql, it is host-only controller, for later imx6, it is otg's */
7387 #define MX6_USB_OTG2_PHY_CTRL 0x1c
....@@ -86,6 +100,42 @@
86100 #define MX7D_USB_VBUS_WAKEUP_SOURCE_AVALID MX7D_USB_VBUS_WAKEUP_SOURCE(1)
87101 #define MX7D_USB_VBUS_WAKEUP_SOURCE_BVALID MX7D_USB_VBUS_WAKEUP_SOURCE(2)
88102 #define MX7D_USB_VBUS_WAKEUP_SOURCE_SESS_END MX7D_USB_VBUS_WAKEUP_SOURCE(3)
103
+#define MX7D_USBNC_AUTO_RESUME BIT(2)
104
+/* The default DM/DP value is pull-down */
105
+#define MX7D_USBNC_USB_CTRL2_OPMODE(v) (v << 6)
106
+#define MX7D_USBNC_USB_CTRL2_OPMODE_NON_DRIVING MX7D_USBNC_USB_CTRL2_OPMODE(1)
107
+#define MX7D_USBNC_USB_CTRL2_OPMODE_OVERRIDE_MASK (BIT(7) | BIT(6))
108
+#define MX7D_USBNC_USB_CTRL2_OPMODE_OVERRIDE_EN BIT(8)
109
+#define MX7D_USBNC_USB_CTRL2_DP_OVERRIDE_VAL BIT(12)
110
+#define MX7D_USBNC_USB_CTRL2_DP_OVERRIDE_EN BIT(13)
111
+#define MX7D_USBNC_USB_CTRL2_DM_OVERRIDE_VAL BIT(14)
112
+#define MX7D_USBNC_USB_CTRL2_DM_OVERRIDE_EN BIT(15)
113
+#define MX7D_USBNC_USB_CTRL2_DP_DM_MASK (BIT(12) | BIT(13) | \
114
+ BIT(14) | BIT(15))
115
+
116
+#define MX7D_USB_OTG_PHY_CFG1 0x30
117
+#define MX7D_USB_OTG_PHY_CFG2_CHRG_CHRGSEL BIT(0)
118
+#define MX7D_USB_OTG_PHY_CFG2_CHRG_VDATDETENB0 BIT(1)
119
+#define MX7D_USB_OTG_PHY_CFG2_CHRG_VDATSRCENB0 BIT(2)
120
+#define MX7D_USB_OTG_PHY_CFG2_CHRG_DCDENB BIT(3)
121
+#define MX7D_USB_OTG_PHY_CFG2_DRVVBUS0 BIT(16)
122
+
123
+#define MX7D_USB_OTG_PHY_CFG2 0x34
124
+
125
+#define MX7D_USB_OTG_PHY_STATUS 0x3c
126
+#define MX7D_USB_OTG_PHY_STATUS_LINE_STATE0 BIT(0)
127
+#define MX7D_USB_OTG_PHY_STATUS_LINE_STATE1 BIT(1)
128
+#define MX7D_USB_OTG_PHY_STATUS_VBUS_VLD BIT(3)
129
+#define MX7D_USB_OTG_PHY_STATUS_CHRGDET BIT(29)
130
+
131
+#define MX7D_USB_OTG_PHY_CFG1 0x30
132
+#define TXPREEMPAMPTUNE0_BIT 28
133
+#define TXPREEMPAMPTUNE0_MASK (3 << 28)
134
+#define TXVREFTUNE0_BIT 20
135
+#define TXVREFTUNE0_MASK (0xf << 20)
136
+
137
+#define MX6_USB_OTG_WAKEUP_BITS (MX6_BM_WAKEUP_ENABLE | MX6_BM_VBUS_WAKEUP | \
138
+ MX6_BM_ID_WAKEUP | MX6SX_BM_DPDM_WAKEUP_EN)
89139
90140 struct usbmisc_ops {
91141 /* It's called once when probe a usb device */
....@@ -94,6 +144,12 @@
94144 int (*post)(struct imx_usbmisc_data *data);
95145 /* It's called when we need to enable/disable usb wakeup */
96146 int (*set_wakeup)(struct imx_usbmisc_data *data, bool enabled);
147
+ /* It's called before setting portsc.suspendM */
148
+ int (*hsic_set_connect)(struct imx_usbmisc_data *data);
149
+ /* It's called during suspend/resume */
150
+ int (*hsic_set_clk)(struct imx_usbmisc_data *data, bool enabled);
151
+ /* usb charger detection */
152
+ int (*charger_detection)(struct imx_usbmisc_data *data);
97153 };
98154
99155 struct imx_usbmisc {
....@@ -120,6 +176,14 @@
120176 val &= ~(MX25_OTG_SIC_MASK | MX25_OTG_PP_BIT);
121177 val |= (MX25_EHCI_INTERFACE_DIFF_UNI & MX25_EHCI_INTERFACE_MASK) << MX25_OTG_SIC_SHIFT;
122178 val |= (MX25_OTG_PM_BIT | MX25_OTG_OCPOL_BIT);
179
+
180
+ /*
181
+ * If the polarity is not configured assume active high for
182
+ * historical reasons.
183
+ */
184
+ if (data->oc_pol_configured && data->oc_pol_active_low)
185
+ val &= ~MX25_OTG_OCPOL_BIT;
186
+
123187 writel(val, usbmisc->base);
124188 break;
125189 case 1:
....@@ -128,6 +192,13 @@
128192 val |= (MX25_EHCI_INTERFACE_SINGLE_UNI & MX25_EHCI_INTERFACE_MASK) << MX25_H1_SIC_SHIFT;
129193 val |= (MX25_H1_PM_BIT | MX25_H1_OCPOL_BIT | MX25_H1_TLL_BIT |
130194 MX25_H1_USBTE_BIT | MX25_H1_IPPUE_DOWN_BIT);
195
+
196
+ /*
197
+ * If the polarity is not configured assume active high for
198
+ * historical reasons.
199
+ */
200
+ if (data->oc_pol_configured && data->oc_pol_active_low)
201
+ val &= ~MX25_H1_OCPOL_BIT;
131202
132203 writel(val, usbmisc->base);
133204
....@@ -298,14 +369,25 @@
298369 return 0;
299370 }
300371
372
+static u32 usbmisc_wakeup_setting(struct imx_usbmisc_data *data)
373
+{
374
+ u32 wakeup_setting = MX6_USB_OTG_WAKEUP_BITS;
375
+
376
+ if (data->ext_id || data->available_role != USB_DR_MODE_OTG)
377
+ wakeup_setting &= ~MX6_BM_ID_WAKEUP;
378
+
379
+ if (data->ext_vbus || data->available_role == USB_DR_MODE_HOST)
380
+ wakeup_setting &= ~MX6_BM_VBUS_WAKEUP;
381
+
382
+ return wakeup_setting;
383
+}
384
+
301385 static int usbmisc_imx6q_set_wakeup
302386 (struct imx_usbmisc_data *data, bool enabled)
303387 {
304388 struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev);
305389 unsigned long flags;
306390 u32 val;
307
- u32 wakeup_setting = (MX6_BM_WAKEUP_ENABLE |
308
- MX6_BM_VBUS_WAKEUP | MX6_BM_ID_WAKEUP);
309391 int ret = 0;
310392
311393 if (data->index > 3)
....@@ -314,11 +396,12 @@
314396 spin_lock_irqsave(&usbmisc->lock, flags);
315397 val = readl(usbmisc->base + data->index * 4);
316398 if (enabled) {
317
- val |= wakeup_setting;
399
+ val &= ~MX6_USB_OTG_WAKEUP_BITS;
400
+ val |= usbmisc_wakeup_setting(data);
318401 } else {
319402 if (val & MX6_BM_WAKEUP_INTR)
320403 pr_debug("wakeup int at ci_hdrc.%d\n", data->index);
321
- val &= ~wakeup_setting;
404
+ val &= ~MX6_USB_OTG_WAKEUP_BITS;
322405 }
323406 writel(val, usbmisc->base + data->index * 4);
324407 spin_unlock_irqrestore(&usbmisc->lock, flags);
....@@ -340,12 +423,21 @@
340423 reg = readl(usbmisc->base + data->index * 4);
341424 if (data->disable_oc) {
342425 reg |= MX6_BM_OVER_CUR_DIS;
343
- } else if (data->oc_polarity == 1) {
344
- /* High active */
345
- reg &= ~(MX6_BM_OVER_CUR_DIS | MX6_BM_OVER_CUR_POLARITY);
346426 } else {
347
- reg &= ~(MX6_BM_OVER_CUR_DIS);
427
+ reg &= ~MX6_BM_OVER_CUR_DIS;
428
+
429
+ /*
430
+ * If the polarity is not configured keep it as setup by the
431
+ * bootloader.
432
+ */
433
+ if (data->oc_pol_configured && data->oc_pol_active_low)
434
+ reg |= MX6_BM_OVER_CUR_POLARITY;
435
+ else if (data->oc_pol_configured)
436
+ reg &= ~MX6_BM_OVER_CUR_POLARITY;
348437 }
438
+ /* If the polarity is not set keep it as setup by the bootlader */
439
+ if (data->pwr_pol == 1)
440
+ reg |= MX6_BM_PWR_POLARITY;
349441 writel(reg, usbmisc->base + data->index * 4);
350442
351443 /* SoC non-burst setting */
....@@ -353,12 +445,97 @@
353445 writel(reg | MX6_BM_NON_BURST_SETTING,
354446 usbmisc->base + data->index * 4);
355447
448
+ /* For HSIC controller */
449
+ if (data->hsic) {
450
+ reg = readl(usbmisc->base + data->index * 4);
451
+ writel(reg | MX6_BM_UTMI_ON_CLOCK,
452
+ usbmisc->base + data->index * 4);
453
+ reg = readl(usbmisc->base + MX6_USB_HSIC_CTRL_OFFSET
454
+ + (data->index - 2) * 4);
455
+ reg |= MX6_BM_HSIC_EN | MX6_BM_HSIC_CLK_ON;
456
+ writel(reg, usbmisc->base + MX6_USB_HSIC_CTRL_OFFSET
457
+ + (data->index - 2) * 4);
458
+ }
459
+
356460 spin_unlock_irqrestore(&usbmisc->lock, flags);
357461
358462 usbmisc_imx6q_set_wakeup(data, false);
359463
360464 return 0;
361465 }
466
+
467
+static int usbmisc_imx6_hsic_get_reg_offset(struct imx_usbmisc_data *data)
468
+{
469
+ int offset, ret = 0;
470
+
471
+ if (data->index == 2 || data->index == 3) {
472
+ offset = (data->index - 2) * 4;
473
+ } else if (data->index == 0) {
474
+ /*
475
+ * For SoCs like i.MX7D and later, each USB controller has
476
+ * its own non-core register region. For SoCs before i.MX7D,
477
+ * the first two USB controllers are non-HSIC controllers.
478
+ */
479
+ offset = 0;
480
+ } else {
481
+ dev_err(data->dev, "index is error for usbmisc\n");
482
+ ret = -EINVAL;
483
+ }
484
+
485
+ return ret ? ret : offset;
486
+}
487
+
488
+static int usbmisc_imx6_hsic_set_connect(struct imx_usbmisc_data *data)
489
+{
490
+ unsigned long flags;
491
+ u32 val;
492
+ struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev);
493
+ int offset;
494
+
495
+ spin_lock_irqsave(&usbmisc->lock, flags);
496
+ offset = usbmisc_imx6_hsic_get_reg_offset(data);
497
+ if (offset < 0) {
498
+ spin_unlock_irqrestore(&usbmisc->lock, flags);
499
+ return offset;
500
+ }
501
+
502
+ val = readl(usbmisc->base + MX6_USB_HSIC_CTRL_OFFSET + offset);
503
+ if (!(val & MX6_BM_HSIC_DEV_CONN))
504
+ writel(val | MX6_BM_HSIC_DEV_CONN,
505
+ usbmisc->base + MX6_USB_HSIC_CTRL_OFFSET + offset);
506
+
507
+ spin_unlock_irqrestore(&usbmisc->lock, flags);
508
+
509
+ return 0;
510
+}
511
+
512
+static int usbmisc_imx6_hsic_set_clk(struct imx_usbmisc_data *data, bool on)
513
+{
514
+ unsigned long flags;
515
+ u32 val;
516
+ struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev);
517
+ int offset;
518
+
519
+ spin_lock_irqsave(&usbmisc->lock, flags);
520
+ offset = usbmisc_imx6_hsic_get_reg_offset(data);
521
+ if (offset < 0) {
522
+ spin_unlock_irqrestore(&usbmisc->lock, flags);
523
+ return offset;
524
+ }
525
+
526
+ val = readl(usbmisc->base + MX6_USB_HSIC_CTRL_OFFSET + offset);
527
+ val |= MX6_BM_HSIC_EN | MX6_BM_HSIC_CLK_ON;
528
+ if (on)
529
+ val |= MX6_BM_HSIC_CLK_ON;
530
+ else
531
+ val &= ~MX6_BM_HSIC_CLK_ON;
532
+
533
+ writel(val, usbmisc->base + MX6_USB_HSIC_CTRL_OFFSET + offset);
534
+ spin_unlock_irqrestore(&usbmisc->lock, flags);
535
+
536
+ return 0;
537
+}
538
+
362539
363540 static int usbmisc_imx6sx_init(struct imx_usbmisc_data *data)
364541 {
....@@ -383,6 +560,13 @@
383560 writel(val & ~MX6SX_BM_DPDM_WAKEUP_EN,
384561 usbmisc->base + data->index * 4);
385562 spin_unlock_irqrestore(&usbmisc->lock, flags);
563
+ }
564
+
565
+ /* For HSIC controller */
566
+ if (data->hsic) {
567
+ val = readl(usbmisc->base + MX6_USB_HSIC_CTRL_OFFSET);
568
+ val |= MX6SX_BM_HSIC_AUTO_RESUME;
569
+ writel(val, usbmisc->base + MX6_USB_HSIC_CTRL_OFFSET);
386570 }
387571
388572 return 0;
....@@ -414,17 +598,17 @@
414598 struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev);
415599 unsigned long flags;
416600 u32 val;
417
- u32 wakeup_setting = (MX6_BM_WAKEUP_ENABLE |
418
- MX6_BM_VBUS_WAKEUP | MX6_BM_ID_WAKEUP);
419601
420602 spin_lock_irqsave(&usbmisc->lock, flags);
421603 val = readl(usbmisc->base);
422604 if (enabled) {
423
- writel(val | wakeup_setting, usbmisc->base);
605
+ val &= ~MX6_USB_OTG_WAKEUP_BITS;
606
+ val |= usbmisc_wakeup_setting(data);
607
+ writel(val, usbmisc->base);
424608 } else {
425609 if (val & MX6_BM_WAKEUP_INTR)
426610 dev_dbg(data->dev, "wakeup int\n");
427
- writel(val & ~wakeup_setting, usbmisc->base);
611
+ writel(val & ~MX6_USB_OTG_WAKEUP_BITS, usbmisc->base);
428612 }
429613 spin_unlock_irqrestore(&usbmisc->lock, flags);
430614
....@@ -444,16 +628,310 @@
444628 reg = readl(usbmisc->base);
445629 if (data->disable_oc) {
446630 reg |= MX6_BM_OVER_CUR_DIS;
447
- } else if (data->oc_polarity == 1) {
448
- /* High active */
449
- reg &= ~(MX6_BM_OVER_CUR_DIS | MX6_BM_OVER_CUR_POLARITY);
631
+ } else {
632
+ reg &= ~MX6_BM_OVER_CUR_DIS;
633
+
634
+ /*
635
+ * If the polarity is not configured keep it as setup by the
636
+ * bootloader.
637
+ */
638
+ if (data->oc_pol_configured && data->oc_pol_active_low)
639
+ reg |= MX6_BM_OVER_CUR_POLARITY;
640
+ else if (data->oc_pol_configured)
641
+ reg &= ~MX6_BM_OVER_CUR_POLARITY;
450642 }
643
+ /* If the polarity is not set keep it as setup by the bootlader */
644
+ if (data->pwr_pol == 1)
645
+ reg |= MX6_BM_PWR_POLARITY;
451646 writel(reg, usbmisc->base);
452647
453
- reg = readl(usbmisc->base + MX7D_USBNC_USB_CTRL2);
454
- reg &= ~MX7D_USB_VBUS_WAKEUP_SOURCE_MASK;
455
- writel(reg | MX7D_USB_VBUS_WAKEUP_SOURCE_BVALID,
456
- usbmisc->base + MX7D_USBNC_USB_CTRL2);
648
+ /* SoC non-burst setting */
649
+ reg = readl(usbmisc->base);
650
+ writel(reg | MX6_BM_NON_BURST_SETTING, usbmisc->base);
651
+
652
+ if (!data->hsic) {
653
+ reg = readl(usbmisc->base + MX7D_USBNC_USB_CTRL2);
654
+ reg &= ~MX7D_USB_VBUS_WAKEUP_SOURCE_MASK;
655
+ writel(reg | MX7D_USB_VBUS_WAKEUP_SOURCE_BVALID
656
+ | MX7D_USBNC_AUTO_RESUME,
657
+ usbmisc->base + MX7D_USBNC_USB_CTRL2);
658
+ /* PHY tuning for signal quality */
659
+ reg = readl(usbmisc->base + MX7D_USB_OTG_PHY_CFG1);
660
+ if (data->emp_curr_control >= 0 &&
661
+ data->emp_curr_control <=
662
+ (TXPREEMPAMPTUNE0_MASK >> TXPREEMPAMPTUNE0_BIT)) {
663
+ reg &= ~TXPREEMPAMPTUNE0_MASK;
664
+ reg |= (data->emp_curr_control << TXPREEMPAMPTUNE0_BIT);
665
+ }
666
+
667
+ if (data->dc_vol_level_adjust >= 0 &&
668
+ data->dc_vol_level_adjust <=
669
+ (TXVREFTUNE0_MASK >> TXVREFTUNE0_BIT)) {
670
+ reg &= ~TXVREFTUNE0_MASK;
671
+ reg |= (data->dc_vol_level_adjust << TXVREFTUNE0_BIT);
672
+ }
673
+
674
+ writel(reg, usbmisc->base + MX7D_USB_OTG_PHY_CFG1);
675
+ }
676
+
677
+ spin_unlock_irqrestore(&usbmisc->lock, flags);
678
+
679
+ usbmisc_imx7d_set_wakeup(data, false);
680
+
681
+ return 0;
682
+}
683
+
684
+static int imx7d_charger_secondary_detection(struct imx_usbmisc_data *data)
685
+{
686
+ struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev);
687
+ struct usb_phy *usb_phy = data->usb_phy;
688
+ int val;
689
+ unsigned long flags;
690
+
691
+ /* Clear VDATSRCENB0 to disable VDP_SRC and IDM_SNK required by BC 1.2 spec */
692
+ spin_lock_irqsave(&usbmisc->lock, flags);
693
+ val = readl(usbmisc->base + MX7D_USB_OTG_PHY_CFG2);
694
+ val &= ~MX7D_USB_OTG_PHY_CFG2_CHRG_VDATSRCENB0;
695
+ writel(val, usbmisc->base + MX7D_USB_OTG_PHY_CFG2);
696
+ spin_unlock_irqrestore(&usbmisc->lock, flags);
697
+
698
+ /* TVDMSRC_DIS */
699
+ msleep(20);
700
+
701
+ /* VDM_SRC is connected to D- and IDP_SINK is connected to D+ */
702
+ spin_lock_irqsave(&usbmisc->lock, flags);
703
+ val = readl(usbmisc->base + MX7D_USB_OTG_PHY_CFG2);
704
+ writel(val | MX7D_USB_OTG_PHY_CFG2_CHRG_VDATSRCENB0 |
705
+ MX7D_USB_OTG_PHY_CFG2_CHRG_VDATDETENB0 |
706
+ MX7D_USB_OTG_PHY_CFG2_CHRG_CHRGSEL,
707
+ usbmisc->base + MX7D_USB_OTG_PHY_CFG2);
708
+ spin_unlock_irqrestore(&usbmisc->lock, flags);
709
+
710
+ /* TVDMSRC_ON */
711
+ msleep(40);
712
+
713
+ /*
714
+ * Per BC 1.2, check voltage of D+:
715
+ * DCP: if greater than VDAT_REF;
716
+ * CDP: if less than VDAT_REF.
717
+ */
718
+ val = readl(usbmisc->base + MX7D_USB_OTG_PHY_STATUS);
719
+ if (val & MX7D_USB_OTG_PHY_STATUS_CHRGDET) {
720
+ dev_dbg(data->dev, "It is a dedicate charging port\n");
721
+ usb_phy->chg_type = DCP_TYPE;
722
+ } else {
723
+ dev_dbg(data->dev, "It is a charging downstream port\n");
724
+ usb_phy->chg_type = CDP_TYPE;
725
+ }
726
+
727
+ return 0;
728
+}
729
+
730
+static void imx7_disable_charger_detector(struct imx_usbmisc_data *data)
731
+{
732
+ struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev);
733
+ unsigned long flags;
734
+ u32 val;
735
+
736
+ spin_lock_irqsave(&usbmisc->lock, flags);
737
+ val = readl(usbmisc->base + MX7D_USB_OTG_PHY_CFG2);
738
+ val &= ~(MX7D_USB_OTG_PHY_CFG2_CHRG_DCDENB |
739
+ MX7D_USB_OTG_PHY_CFG2_CHRG_VDATSRCENB0 |
740
+ MX7D_USB_OTG_PHY_CFG2_CHRG_VDATDETENB0 |
741
+ MX7D_USB_OTG_PHY_CFG2_CHRG_CHRGSEL);
742
+ writel(val, usbmisc->base + MX7D_USB_OTG_PHY_CFG2);
743
+
744
+ /* Set OPMODE to be 2'b00 and disable its override */
745
+ val = readl(usbmisc->base + MX7D_USBNC_USB_CTRL2);
746
+ val &= ~MX7D_USBNC_USB_CTRL2_OPMODE_OVERRIDE_MASK;
747
+ writel(val, usbmisc->base + MX7D_USBNC_USB_CTRL2);
748
+
749
+ val = readl(usbmisc->base + MX7D_USBNC_USB_CTRL2);
750
+ writel(val & ~MX7D_USBNC_USB_CTRL2_OPMODE_OVERRIDE_EN,
751
+ usbmisc->base + MX7D_USBNC_USB_CTRL2);
752
+ spin_unlock_irqrestore(&usbmisc->lock, flags);
753
+}
754
+
755
+static int imx7d_charger_data_contact_detect(struct imx_usbmisc_data *data)
756
+{
757
+ struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev);
758
+ unsigned long flags;
759
+ u32 val;
760
+ int i, data_pin_contact_count = 0;
761
+
762
+ /* Enable Data Contact Detect (DCD) per the USB BC 1.2 */
763
+ spin_lock_irqsave(&usbmisc->lock, flags);
764
+ val = readl(usbmisc->base + MX7D_USB_OTG_PHY_CFG2);
765
+ writel(val | MX7D_USB_OTG_PHY_CFG2_CHRG_DCDENB,
766
+ usbmisc->base + MX7D_USB_OTG_PHY_CFG2);
767
+ spin_unlock_irqrestore(&usbmisc->lock, flags);
768
+
769
+ for (i = 0; i < 100; i = i + 1) {
770
+ val = readl(usbmisc->base + MX7D_USB_OTG_PHY_STATUS);
771
+ if (!(val & MX7D_USB_OTG_PHY_STATUS_LINE_STATE0)) {
772
+ if (data_pin_contact_count++ > 5)
773
+ /* Data pin makes contact */
774
+ break;
775
+ usleep_range(5000, 10000);
776
+ } else {
777
+ data_pin_contact_count = 0;
778
+ usleep_range(5000, 6000);
779
+ }
780
+ }
781
+
782
+ /* Disable DCD after finished data contact check */
783
+ spin_lock_irqsave(&usbmisc->lock, flags);
784
+ val = readl(usbmisc->base + MX7D_USB_OTG_PHY_CFG2);
785
+ writel(val & ~MX7D_USB_OTG_PHY_CFG2_CHRG_DCDENB,
786
+ usbmisc->base + MX7D_USB_OTG_PHY_CFG2);
787
+ spin_unlock_irqrestore(&usbmisc->lock, flags);
788
+
789
+ if (i == 100) {
790
+ dev_err(data->dev,
791
+ "VBUS is coming from a dedicated power supply.\n");
792
+ return -ENXIO;
793
+ }
794
+
795
+ return 0;
796
+}
797
+
798
+static int imx7d_charger_primary_detection(struct imx_usbmisc_data *data)
799
+{
800
+ struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev);
801
+ struct usb_phy *usb_phy = data->usb_phy;
802
+ unsigned long flags;
803
+ u32 val;
804
+
805
+ /* VDP_SRC is connected to D+ and IDM_SINK is connected to D- */
806
+ spin_lock_irqsave(&usbmisc->lock, flags);
807
+ val = readl(usbmisc->base + MX7D_USB_OTG_PHY_CFG2);
808
+ val &= ~MX7D_USB_OTG_PHY_CFG2_CHRG_CHRGSEL;
809
+ writel(val | MX7D_USB_OTG_PHY_CFG2_CHRG_VDATSRCENB0 |
810
+ MX7D_USB_OTG_PHY_CFG2_CHRG_VDATDETENB0,
811
+ usbmisc->base + MX7D_USB_OTG_PHY_CFG2);
812
+ spin_unlock_irqrestore(&usbmisc->lock, flags);
813
+
814
+ /* TVDPSRC_ON */
815
+ msleep(40);
816
+
817
+ /* Check if D- is less than VDAT_REF to determine an SDP per BC 1.2 */
818
+ val = readl(usbmisc->base + MX7D_USB_OTG_PHY_STATUS);
819
+ if (!(val & MX7D_USB_OTG_PHY_STATUS_CHRGDET)) {
820
+ dev_dbg(data->dev, "It is a standard downstream port\n");
821
+ usb_phy->chg_type = SDP_TYPE;
822
+ }
823
+
824
+ return 0;
825
+}
826
+
827
+/*
828
+ * Whole charger detection process:
829
+ * 1. OPMODE override to be non-driving
830
+ * 2. Data contact check
831
+ * 3. Primary detection
832
+ * 4. Secondary detection
833
+ * 5. Disable charger detection
834
+ */
835
+static int imx7d_charger_detection(struct imx_usbmisc_data *data)
836
+{
837
+ struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev);
838
+ struct usb_phy *usb_phy = data->usb_phy;
839
+ unsigned long flags;
840
+ u32 val;
841
+ int ret;
842
+
843
+ /* Check if vbus is valid */
844
+ val = readl(usbmisc->base + MX7D_USB_OTG_PHY_STATUS);
845
+ if (!(val & MX7D_USB_OTG_PHY_STATUS_VBUS_VLD)) {
846
+ dev_err(data->dev, "vbus is error\n");
847
+ return -EINVAL;
848
+ }
849
+
850
+ /*
851
+ * Keep OPMODE to be non-driving mode during the whole
852
+ * charger detection process.
853
+ */
854
+ spin_lock_irqsave(&usbmisc->lock, flags);
855
+ val = readl(usbmisc->base + MX7D_USBNC_USB_CTRL2);
856
+ val &= ~MX7D_USBNC_USB_CTRL2_OPMODE_OVERRIDE_MASK;
857
+ val |= MX7D_USBNC_USB_CTRL2_OPMODE_NON_DRIVING;
858
+ writel(val, usbmisc->base + MX7D_USBNC_USB_CTRL2);
859
+
860
+ val = readl(usbmisc->base + MX7D_USBNC_USB_CTRL2);
861
+ writel(val | MX7D_USBNC_USB_CTRL2_OPMODE_OVERRIDE_EN,
862
+ usbmisc->base + MX7D_USBNC_USB_CTRL2);
863
+ spin_unlock_irqrestore(&usbmisc->lock, flags);
864
+
865
+ ret = imx7d_charger_data_contact_detect(data);
866
+ if (ret)
867
+ return ret;
868
+
869
+ ret = imx7d_charger_primary_detection(data);
870
+ if (!ret && usb_phy->chg_type != SDP_TYPE)
871
+ ret = imx7d_charger_secondary_detection(data);
872
+
873
+ imx7_disable_charger_detector(data);
874
+
875
+ return ret;
876
+}
877
+
878
+static int usbmisc_imx7ulp_init(struct imx_usbmisc_data *data)
879
+{
880
+ struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev);
881
+ unsigned long flags;
882
+ u32 reg;
883
+
884
+ if (data->index >= 1)
885
+ return -EINVAL;
886
+
887
+ spin_lock_irqsave(&usbmisc->lock, flags);
888
+ reg = readl(usbmisc->base);
889
+ if (data->disable_oc) {
890
+ reg |= MX6_BM_OVER_CUR_DIS;
891
+ } else {
892
+ reg &= ~MX6_BM_OVER_CUR_DIS;
893
+
894
+ /*
895
+ * If the polarity is not configured keep it as setup by the
896
+ * bootloader.
897
+ */
898
+ if (data->oc_pol_configured && data->oc_pol_active_low)
899
+ reg |= MX6_BM_OVER_CUR_POLARITY;
900
+ else if (data->oc_pol_configured)
901
+ reg &= ~MX6_BM_OVER_CUR_POLARITY;
902
+ }
903
+ /* If the polarity is not set keep it as setup by the bootlader */
904
+ if (data->pwr_pol == 1)
905
+ reg |= MX6_BM_PWR_POLARITY;
906
+
907
+ writel(reg, usbmisc->base);
908
+
909
+ /* SoC non-burst setting */
910
+ reg = readl(usbmisc->base);
911
+ writel(reg | MX6_BM_NON_BURST_SETTING, usbmisc->base);
912
+
913
+ if (data->hsic) {
914
+ reg = readl(usbmisc->base);
915
+ writel(reg | MX6_BM_UTMI_ON_CLOCK, usbmisc->base);
916
+
917
+ reg = readl(usbmisc->base + MX6_USB_HSIC_CTRL_OFFSET);
918
+ reg |= MX6_BM_HSIC_EN | MX6_BM_HSIC_CLK_ON;
919
+ writel(reg, usbmisc->base + MX6_USB_HSIC_CTRL_OFFSET);
920
+
921
+ /*
922
+ * For non-HSIC controller, the autoresume is enabled
923
+ * at MXS PHY driver (usbphy_ctrl bit18).
924
+ */
925
+ reg = readl(usbmisc->base + MX7D_USBNC_USB_CTRL2);
926
+ writel(reg | MX7D_USBNC_AUTO_RESUME,
927
+ usbmisc->base + MX7D_USBNC_USB_CTRL2);
928
+ } else {
929
+ reg = readl(usbmisc->base + MX7D_USBNC_USB_CTRL2);
930
+ reg &= ~MX7D_USB_VBUS_WAKEUP_SOURCE_MASK;
931
+ writel(reg | MX7D_USB_VBUS_WAKEUP_SOURCE_BVALID,
932
+ usbmisc->base + MX7D_USBNC_USB_CTRL2);
933
+ }
934
+
457935 spin_unlock_irqrestore(&usbmisc->lock, flags);
458936
459937 usbmisc_imx7d_set_wakeup(data, false);
....@@ -481,6 +959,8 @@
481959 static const struct usbmisc_ops imx6q_usbmisc_ops = {
482960 .set_wakeup = usbmisc_imx6q_set_wakeup,
483961 .init = usbmisc_imx6q_init,
962
+ .hsic_set_connect = usbmisc_imx6_hsic_set_connect,
963
+ .hsic_set_clk = usbmisc_imx6_hsic_set_clk,
484964 };
485965
486966 static const struct usbmisc_ops vf610_usbmisc_ops = {
....@@ -490,11 +970,21 @@
490970 static const struct usbmisc_ops imx6sx_usbmisc_ops = {
491971 .set_wakeup = usbmisc_imx6q_set_wakeup,
492972 .init = usbmisc_imx6sx_init,
973
+ .hsic_set_connect = usbmisc_imx6_hsic_set_connect,
974
+ .hsic_set_clk = usbmisc_imx6_hsic_set_clk,
493975 };
494976
495977 static const struct usbmisc_ops imx7d_usbmisc_ops = {
496978 .init = usbmisc_imx7d_init,
497979 .set_wakeup = usbmisc_imx7d_set_wakeup,
980
+ .charger_detection = imx7d_charger_detection,
981
+};
982
+
983
+static const struct usbmisc_ops imx7ulp_usbmisc_ops = {
984
+ .init = usbmisc_imx7ulp_init,
985
+ .set_wakeup = usbmisc_imx7d_set_wakeup,
986
+ .hsic_set_connect = usbmisc_imx6_hsic_set_connect,
987
+ .hsic_set_clk = usbmisc_imx6_hsic_set_clk,
498988 };
499989
500990 static inline bool is_imx53_usbmisc(struct imx_usbmisc_data *data)
....@@ -546,6 +1036,66 @@
5461036 }
5471037 EXPORT_SYMBOL_GPL(imx_usbmisc_set_wakeup);
5481038
1039
+int imx_usbmisc_hsic_set_connect(struct imx_usbmisc_data *data)
1040
+{
1041
+ struct imx_usbmisc *usbmisc;
1042
+
1043
+ if (!data)
1044
+ return 0;
1045
+
1046
+ usbmisc = dev_get_drvdata(data->dev);
1047
+ if (!usbmisc->ops->hsic_set_connect || !data->hsic)
1048
+ return 0;
1049
+ return usbmisc->ops->hsic_set_connect(data);
1050
+}
1051
+EXPORT_SYMBOL_GPL(imx_usbmisc_hsic_set_connect);
1052
+
1053
+int imx_usbmisc_hsic_set_clk(struct imx_usbmisc_data *data, bool on)
1054
+{
1055
+ struct imx_usbmisc *usbmisc;
1056
+
1057
+ if (!data)
1058
+ return 0;
1059
+
1060
+ usbmisc = dev_get_drvdata(data->dev);
1061
+ if (!usbmisc->ops->hsic_set_clk || !data->hsic)
1062
+ return 0;
1063
+ return usbmisc->ops->hsic_set_clk(data, on);
1064
+}
1065
+EXPORT_SYMBOL_GPL(imx_usbmisc_hsic_set_clk);
1066
+
1067
+int imx_usbmisc_charger_detection(struct imx_usbmisc_data *data, bool connect)
1068
+{
1069
+ struct imx_usbmisc *usbmisc;
1070
+ struct usb_phy *usb_phy;
1071
+ int ret = 0;
1072
+
1073
+ if (!data)
1074
+ return -EINVAL;
1075
+
1076
+ usbmisc = dev_get_drvdata(data->dev);
1077
+ usb_phy = data->usb_phy;
1078
+ if (!usbmisc->ops->charger_detection)
1079
+ return -ENOTSUPP;
1080
+
1081
+ if (connect) {
1082
+ ret = usbmisc->ops->charger_detection(data);
1083
+ if (ret) {
1084
+ dev_err(data->dev,
1085
+ "Error occurs during detection: %d\n",
1086
+ ret);
1087
+ usb_phy->chg_state = USB_CHARGER_ABSENT;
1088
+ } else {
1089
+ usb_phy->chg_state = USB_CHARGER_PRESENT;
1090
+ }
1091
+ } else {
1092
+ usb_phy->chg_state = USB_CHARGER_ABSENT;
1093
+ usb_phy->chg_type = UNKNOWN_TYPE;
1094
+ }
1095
+ return ret;
1096
+}
1097
+EXPORT_SYMBOL_GPL(imx_usbmisc_charger_detection);
1098
+
5491099 static const struct of_device_id usbmisc_imx_dt_ids[] = {
5501100 {
5511101 .compatible = "fsl,imx25-usbmisc",
....@@ -587,13 +1137,16 @@
5871137 .compatible = "fsl,imx7d-usbmisc",
5881138 .data = &imx7d_usbmisc_ops,
5891139 },
1140
+ {
1141
+ .compatible = "fsl,imx7ulp-usbmisc",
1142
+ .data = &imx7ulp_usbmisc_ops,
1143
+ },
5901144 { /* sentinel */ }
5911145 };
5921146 MODULE_DEVICE_TABLE(of, usbmisc_imx_dt_ids);
5931147
5941148 static int usbmisc_imx_probe(struct platform_device *pdev)
5951149 {
596
- struct resource *res;
5971150 struct imx_usbmisc *data;
5981151 const struct of_device_id *of_id;
5991152
....@@ -607,8 +1160,7 @@
6071160
6081161 spin_lock_init(&data->lock);
6091162
610
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
611
- data->base = devm_ioremap_resource(&pdev->dev, res);
1163
+ data->base = devm_platform_ioremap_resource(pdev, 0);
6121164 if (IS_ERR(data->base))
6131165 return PTR_ERR(data->base);
6141166
....@@ -635,6 +1187,6 @@
6351187 module_platform_driver(usbmisc_imx_driver);
6361188
6371189 MODULE_ALIAS("platform:usbmisc-imx");
638
-MODULE_LICENSE("GPL v2");
1190
+MODULE_LICENSE("GPL");
6391191 MODULE_DESCRIPTION("driver for imx usb non-core registers");
6401192 MODULE_AUTHOR("Richard Zhao <richard.zhao@freescale.com>");