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