linux/drivers/usb/dwc3/dwc3-qcom.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
   3 *
   4 * Inspired by dwc3-of-simple.c
   5 */
   6
   7#include <linux/acpi.h>
   8#include <linux/io.h>
   9#include <linux/of.h>
  10#include <linux/clk.h>
  11#include <linux/irq.h>
  12#include <linux/of_clk.h>
  13#include <linux/module.h>
  14#include <linux/kernel.h>
  15#include <linux/extcon.h>
  16#include <linux/interconnect.h>
  17#include <linux/of_platform.h>
  18#include <linux/platform_device.h>
  19#include <linux/phy/phy.h>
  20#include <linux/usb/of.h>
  21#include <linux/reset.h>
  22#include <linux/iopoll.h>
  23
  24#include "core.h"
  25
  26/* USB QSCRATCH Hardware registers */
  27#define QSCRATCH_HS_PHY_CTRL                    0x10
  28#define UTMI_OTG_VBUS_VALID                     BIT(20)
  29#define SW_SESSVLD_SEL                          BIT(28)
  30
  31#define QSCRATCH_SS_PHY_CTRL                    0x30
  32#define LANE0_PWR_PRESENT                       BIT(24)
  33
  34#define QSCRATCH_GENERAL_CFG                    0x08
  35#define PIPE_UTMI_CLK_SEL                       BIT(0)
  36#define PIPE3_PHYSTATUS_SW                      BIT(3)
  37#define PIPE_UTMI_CLK_DIS                       BIT(8)
  38
  39#define PWR_EVNT_IRQ_STAT_REG                   0x58
  40#define PWR_EVNT_LPM_IN_L2_MASK                 BIT(4)
  41#define PWR_EVNT_LPM_OUT_L2_MASK                BIT(5)
  42
  43#define SDM845_QSCRATCH_BASE_OFFSET             0xf8800
  44#define SDM845_QSCRATCH_SIZE                    0x400
  45#define SDM845_DWC3_CORE_SIZE                   0xcd00
  46
  47/* Interconnect path bandwidths in MBps */
  48#define USB_MEMORY_AVG_HS_BW MBps_to_icc(240)
  49#define USB_MEMORY_PEAK_HS_BW MBps_to_icc(700)
  50#define USB_MEMORY_AVG_SS_BW  MBps_to_icc(1000)
  51#define USB_MEMORY_PEAK_SS_BW MBps_to_icc(2500)
  52#define APPS_USB_AVG_BW 0
  53#define APPS_USB_PEAK_BW MBps_to_icc(40)
  54
  55struct dwc3_acpi_pdata {
  56        u32                     qscratch_base_offset;
  57        u32                     qscratch_base_size;
  58        u32                     dwc3_core_base_size;
  59        int                     hs_phy_irq_index;
  60        int                     dp_hs_phy_irq_index;
  61        int                     dm_hs_phy_irq_index;
  62        int                     ss_phy_irq_index;
  63        bool                    is_urs;
  64};
  65
  66struct dwc3_qcom {
  67        struct device           *dev;
  68        void __iomem            *qscratch_base;
  69        struct platform_device  *dwc3;
  70        struct platform_device  *urs_usb;
  71        struct clk              **clks;
  72        int                     num_clocks;
  73        struct reset_control    *resets;
  74
  75        int                     hs_phy_irq;
  76        int                     dp_hs_phy_irq;
  77        int                     dm_hs_phy_irq;
  78        int                     ss_phy_irq;
  79
  80        struct extcon_dev       *edev;
  81        struct extcon_dev       *host_edev;
  82        struct notifier_block   vbus_nb;
  83        struct notifier_block   host_nb;
  84
  85        const struct dwc3_acpi_pdata *acpi_pdata;
  86
  87        enum usb_dr_mode        mode;
  88        bool                    is_suspended;
  89        bool                    pm_suspended;
  90        struct icc_path         *icc_path_ddr;
  91        struct icc_path         *icc_path_apps;
  92};
  93
  94static inline void dwc3_qcom_setbits(void __iomem *base, u32 offset, u32 val)
  95{
  96        u32 reg;
  97
  98        reg = readl(base + offset);
  99        reg |= val;
 100        writel(reg, base + offset);
 101
 102        /* ensure that above write is through */
 103        readl(base + offset);
 104}
 105
 106static inline void dwc3_qcom_clrbits(void __iomem *base, u32 offset, u32 val)
 107{
 108        u32 reg;
 109
 110        reg = readl(base + offset);
 111        reg &= ~val;
 112        writel(reg, base + offset);
 113
 114        /* ensure that above write is through */
 115        readl(base + offset);
 116}
 117
 118static void dwc3_qcom_vbus_overrride_enable(struct dwc3_qcom *qcom, bool enable)
 119{
 120        if (enable) {
 121                dwc3_qcom_setbits(qcom->qscratch_base, QSCRATCH_SS_PHY_CTRL,
 122                                  LANE0_PWR_PRESENT);
 123                dwc3_qcom_setbits(qcom->qscratch_base, QSCRATCH_HS_PHY_CTRL,
 124                                  UTMI_OTG_VBUS_VALID | SW_SESSVLD_SEL);
 125        } else {
 126                dwc3_qcom_clrbits(qcom->qscratch_base, QSCRATCH_SS_PHY_CTRL,
 127                                  LANE0_PWR_PRESENT);
 128                dwc3_qcom_clrbits(qcom->qscratch_base, QSCRATCH_HS_PHY_CTRL,
 129                                  UTMI_OTG_VBUS_VALID | SW_SESSVLD_SEL);
 130        }
 131}
 132
 133static int dwc3_qcom_vbus_notifier(struct notifier_block *nb,
 134                                   unsigned long event, void *ptr)
 135{
 136        struct dwc3_qcom *qcom = container_of(nb, struct dwc3_qcom, vbus_nb);
 137
 138        /* enable vbus override for device mode */
 139        dwc3_qcom_vbus_overrride_enable(qcom, event);
 140        qcom->mode = event ? USB_DR_MODE_PERIPHERAL : USB_DR_MODE_HOST;
 141
 142        return NOTIFY_DONE;
 143}
 144
 145static int dwc3_qcom_host_notifier(struct notifier_block *nb,
 146                                   unsigned long event, void *ptr)
 147{
 148        struct dwc3_qcom *qcom = container_of(nb, struct dwc3_qcom, host_nb);
 149
 150        /* disable vbus override in host mode */
 151        dwc3_qcom_vbus_overrride_enable(qcom, !event);
 152        qcom->mode = event ? USB_DR_MODE_HOST : USB_DR_MODE_PERIPHERAL;
 153
 154        return NOTIFY_DONE;
 155}
 156
 157static int dwc3_qcom_register_extcon(struct dwc3_qcom *qcom)
 158{
 159        struct device           *dev = qcom->dev;
 160        struct extcon_dev       *host_edev;
 161        int                     ret;
 162
 163        if (!of_property_read_bool(dev->of_node, "extcon"))
 164                return 0;
 165
 166        qcom->edev = extcon_get_edev_by_phandle(dev, 0);
 167        if (IS_ERR(qcom->edev))
 168                return PTR_ERR(qcom->edev);
 169
 170        qcom->vbus_nb.notifier_call = dwc3_qcom_vbus_notifier;
 171
 172        qcom->host_edev = extcon_get_edev_by_phandle(dev, 1);
 173        if (IS_ERR(qcom->host_edev))
 174                qcom->host_edev = NULL;
 175
 176        ret = devm_extcon_register_notifier(dev, qcom->edev, EXTCON_USB,
 177                                            &qcom->vbus_nb);
 178        if (ret < 0) {
 179                dev_err(dev, "VBUS notifier register failed\n");
 180                return ret;
 181        }
 182
 183        if (qcom->host_edev)
 184                host_edev = qcom->host_edev;
 185        else
 186                host_edev = qcom->edev;
 187
 188        qcom->host_nb.notifier_call = dwc3_qcom_host_notifier;
 189        ret = devm_extcon_register_notifier(dev, host_edev, EXTCON_USB_HOST,
 190                                            &qcom->host_nb);
 191        if (ret < 0) {
 192                dev_err(dev, "Host notifier register failed\n");
 193                return ret;
 194        }
 195
 196        /* Update initial VBUS override based on extcon state */
 197        if (extcon_get_state(qcom->edev, EXTCON_USB) ||
 198            !extcon_get_state(host_edev, EXTCON_USB_HOST))
 199                dwc3_qcom_vbus_notifier(&qcom->vbus_nb, true, qcom->edev);
 200        else
 201                dwc3_qcom_vbus_notifier(&qcom->vbus_nb, false, qcom->edev);
 202
 203        return 0;
 204}
 205
 206static int dwc3_qcom_interconnect_enable(struct dwc3_qcom *qcom)
 207{
 208        int ret;
 209
 210        ret = icc_enable(qcom->icc_path_ddr);
 211        if (ret)
 212                return ret;
 213
 214        ret = icc_enable(qcom->icc_path_apps);
 215        if (ret)
 216                icc_disable(qcom->icc_path_ddr);
 217
 218        return ret;
 219}
 220
 221static int dwc3_qcom_interconnect_disable(struct dwc3_qcom *qcom)
 222{
 223        int ret;
 224
 225        ret = icc_disable(qcom->icc_path_ddr);
 226        if (ret)
 227                return ret;
 228
 229        ret = icc_disable(qcom->icc_path_apps);
 230        if (ret)
 231                icc_enable(qcom->icc_path_ddr);
 232
 233        return ret;
 234}
 235
 236/**
 237 * dwc3_qcom_interconnect_init() - Get interconnect path handles
 238 * and set bandwidth.
 239 * @qcom:                       Pointer to the concerned usb core.
 240 *
 241 */
 242static int dwc3_qcom_interconnect_init(struct dwc3_qcom *qcom)
 243{
 244        struct device *dev = qcom->dev;
 245        int ret;
 246
 247        if (has_acpi_companion(dev))
 248                return 0;
 249
 250        qcom->icc_path_ddr = of_icc_get(dev, "usb-ddr");
 251        if (IS_ERR(qcom->icc_path_ddr)) {
 252                dev_err(dev, "failed to get usb-ddr path: %ld\n",
 253                        PTR_ERR(qcom->icc_path_ddr));
 254                return PTR_ERR(qcom->icc_path_ddr);
 255        }
 256
 257        qcom->icc_path_apps = of_icc_get(dev, "apps-usb");
 258        if (IS_ERR(qcom->icc_path_apps)) {
 259                dev_err(dev, "failed to get apps-usb path: %ld\n",
 260                                PTR_ERR(qcom->icc_path_apps));
 261                return PTR_ERR(qcom->icc_path_apps);
 262        }
 263
 264        if (usb_get_maximum_speed(&qcom->dwc3->dev) >= USB_SPEED_SUPER ||
 265                        usb_get_maximum_speed(&qcom->dwc3->dev) == USB_SPEED_UNKNOWN)
 266                ret = icc_set_bw(qcom->icc_path_ddr,
 267                        USB_MEMORY_AVG_SS_BW, USB_MEMORY_PEAK_SS_BW);
 268        else
 269                ret = icc_set_bw(qcom->icc_path_ddr,
 270                        USB_MEMORY_AVG_HS_BW, USB_MEMORY_PEAK_HS_BW);
 271
 272        if (ret) {
 273                dev_err(dev, "failed to set bandwidth for usb-ddr path: %d\n", ret);
 274                return ret;
 275        }
 276
 277        ret = icc_set_bw(qcom->icc_path_apps,
 278                APPS_USB_AVG_BW, APPS_USB_PEAK_BW);
 279        if (ret) {
 280                dev_err(dev, "failed to set bandwidth for apps-usb path: %d\n", ret);
 281                return ret;
 282        }
 283
 284        return 0;
 285}
 286
 287/**
 288 * dwc3_qcom_interconnect_exit() - Release interconnect path handles
 289 * @qcom:                       Pointer to the concerned usb core.
 290 *
 291 * This function is used to release interconnect path handle.
 292 */
 293static void dwc3_qcom_interconnect_exit(struct dwc3_qcom *qcom)
 294{
 295        icc_put(qcom->icc_path_ddr);
 296        icc_put(qcom->icc_path_apps);
 297}
 298
 299static void dwc3_qcom_disable_interrupts(struct dwc3_qcom *qcom)
 300{
 301        if (qcom->hs_phy_irq) {
 302                disable_irq_wake(qcom->hs_phy_irq);
 303                disable_irq_nosync(qcom->hs_phy_irq);
 304        }
 305
 306        if (qcom->dp_hs_phy_irq) {
 307                disable_irq_wake(qcom->dp_hs_phy_irq);
 308                disable_irq_nosync(qcom->dp_hs_phy_irq);
 309        }
 310
 311        if (qcom->dm_hs_phy_irq) {
 312                disable_irq_wake(qcom->dm_hs_phy_irq);
 313                disable_irq_nosync(qcom->dm_hs_phy_irq);
 314        }
 315
 316        if (qcom->ss_phy_irq) {
 317                disable_irq_wake(qcom->ss_phy_irq);
 318                disable_irq_nosync(qcom->ss_phy_irq);
 319        }
 320}
 321
 322static void dwc3_qcom_enable_interrupts(struct dwc3_qcom *qcom)
 323{
 324        if (qcom->hs_phy_irq) {
 325                enable_irq(qcom->hs_phy_irq);
 326                enable_irq_wake(qcom->hs_phy_irq);
 327        }
 328
 329        if (qcom->dp_hs_phy_irq) {
 330                enable_irq(qcom->dp_hs_phy_irq);
 331                enable_irq_wake(qcom->dp_hs_phy_irq);
 332        }
 333
 334        if (qcom->dm_hs_phy_irq) {
 335                enable_irq(qcom->dm_hs_phy_irq);
 336                enable_irq_wake(qcom->dm_hs_phy_irq);
 337        }
 338
 339        if (qcom->ss_phy_irq) {
 340                enable_irq(qcom->ss_phy_irq);
 341                enable_irq_wake(qcom->ss_phy_irq);
 342        }
 343}
 344
 345static int dwc3_qcom_suspend(struct dwc3_qcom *qcom)
 346{
 347        u32 val;
 348        int i, ret;
 349
 350        if (qcom->is_suspended)
 351                return 0;
 352
 353        val = readl(qcom->qscratch_base + PWR_EVNT_IRQ_STAT_REG);
 354        if (!(val & PWR_EVNT_LPM_IN_L2_MASK))
 355                dev_err(qcom->dev, "HS-PHY not in L2\n");
 356
 357        for (i = qcom->num_clocks - 1; i >= 0; i--)
 358                clk_disable_unprepare(qcom->clks[i]);
 359
 360        ret = dwc3_qcom_interconnect_disable(qcom);
 361        if (ret)
 362                dev_warn(qcom->dev, "failed to disable interconnect: %d\n", ret);
 363
 364        if (device_may_wakeup(qcom->dev))
 365                dwc3_qcom_enable_interrupts(qcom);
 366
 367        qcom->is_suspended = true;
 368
 369        return 0;
 370}
 371
 372static int dwc3_qcom_resume(struct dwc3_qcom *qcom)
 373{
 374        int ret;
 375        int i;
 376
 377        if (!qcom->is_suspended)
 378                return 0;
 379
 380        if (device_may_wakeup(qcom->dev))
 381                dwc3_qcom_disable_interrupts(qcom);
 382
 383        for (i = 0; i < qcom->num_clocks; i++) {
 384                ret = clk_prepare_enable(qcom->clks[i]);
 385                if (ret < 0) {
 386                        while (--i >= 0)
 387                                clk_disable_unprepare(qcom->clks[i]);
 388                        return ret;
 389                }
 390        }
 391
 392        ret = dwc3_qcom_interconnect_enable(qcom);
 393        if (ret)
 394                dev_warn(qcom->dev, "failed to enable interconnect: %d\n", ret);
 395
 396        /* Clear existing events from PHY related to L2 in/out */
 397        dwc3_qcom_setbits(qcom->qscratch_base, PWR_EVNT_IRQ_STAT_REG,
 398                          PWR_EVNT_LPM_IN_L2_MASK | PWR_EVNT_LPM_OUT_L2_MASK);
 399
 400        qcom->is_suspended = false;
 401
 402        return 0;
 403}
 404
 405static irqreturn_t qcom_dwc3_resume_irq(int irq, void *data)
 406{
 407        struct dwc3_qcom *qcom = data;
 408        struct dwc3     *dwc = platform_get_drvdata(qcom->dwc3);
 409
 410        /* If pm_suspended then let pm_resume take care of resuming h/w */
 411        if (qcom->pm_suspended)
 412                return IRQ_HANDLED;
 413
 414        if (dwc->xhci)
 415                pm_runtime_resume(&dwc->xhci->dev);
 416
 417        return IRQ_HANDLED;
 418}
 419
 420static void dwc3_qcom_select_utmi_clk(struct dwc3_qcom *qcom)
 421{
 422        /* Configure dwc3 to use UTMI clock as PIPE clock not present */
 423        dwc3_qcom_setbits(qcom->qscratch_base, QSCRATCH_GENERAL_CFG,
 424                          PIPE_UTMI_CLK_DIS);
 425
 426        usleep_range(100, 1000);
 427
 428        dwc3_qcom_setbits(qcom->qscratch_base, QSCRATCH_GENERAL_CFG,
 429                          PIPE_UTMI_CLK_SEL | PIPE3_PHYSTATUS_SW);
 430
 431        usleep_range(100, 1000);
 432
 433        dwc3_qcom_clrbits(qcom->qscratch_base, QSCRATCH_GENERAL_CFG,
 434                          PIPE_UTMI_CLK_DIS);
 435}
 436
 437static int dwc3_qcom_get_irq(struct platform_device *pdev,
 438                             const char *name, int num)
 439{
 440        struct dwc3_qcom *qcom = platform_get_drvdata(pdev);
 441        struct platform_device *pdev_irq = qcom->urs_usb ? qcom->urs_usb : pdev;
 442        struct device_node *np = pdev->dev.of_node;
 443        int ret;
 444
 445        if (np)
 446                ret = platform_get_irq_byname(pdev_irq, name);
 447        else
 448                ret = platform_get_irq(pdev_irq, num);
 449
 450        return ret;
 451}
 452
 453static int dwc3_qcom_setup_irq(struct platform_device *pdev)
 454{
 455        struct dwc3_qcom *qcom = platform_get_drvdata(pdev);
 456        const struct dwc3_acpi_pdata *pdata = qcom->acpi_pdata;
 457        int irq;
 458        int ret;
 459
 460        irq = dwc3_qcom_get_irq(pdev, "hs_phy_irq",
 461                                pdata ? pdata->hs_phy_irq_index : -1);
 462        if (irq > 0) {
 463                /* Keep wakeup interrupts disabled until suspend */
 464                irq_set_status_flags(irq, IRQ_NOAUTOEN);
 465                ret = devm_request_threaded_irq(qcom->dev, irq, NULL,
 466                                        qcom_dwc3_resume_irq,
 467                                        IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
 468                                        "qcom_dwc3 HS", qcom);
 469                if (ret) {
 470                        dev_err(qcom->dev, "hs_phy_irq failed: %d\n", ret);
 471                        return ret;
 472                }
 473                qcom->hs_phy_irq = irq;
 474        }
 475
 476        irq = dwc3_qcom_get_irq(pdev, "dp_hs_phy_irq",
 477                                pdata ? pdata->dp_hs_phy_irq_index : -1);
 478        if (irq > 0) {
 479                irq_set_status_flags(irq, IRQ_NOAUTOEN);
 480                ret = devm_request_threaded_irq(qcom->dev, irq, NULL,
 481                                        qcom_dwc3_resume_irq,
 482                                        IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
 483                                        "qcom_dwc3 DP_HS", qcom);
 484                if (ret) {
 485                        dev_err(qcom->dev, "dp_hs_phy_irq failed: %d\n", ret);
 486                        return ret;
 487                }
 488                qcom->dp_hs_phy_irq = irq;
 489        }
 490
 491        irq = dwc3_qcom_get_irq(pdev, "dm_hs_phy_irq",
 492                                pdata ? pdata->dm_hs_phy_irq_index : -1);
 493        if (irq > 0) {
 494                irq_set_status_flags(irq, IRQ_NOAUTOEN);
 495                ret = devm_request_threaded_irq(qcom->dev, irq, NULL,
 496                                        qcom_dwc3_resume_irq,
 497                                        IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
 498                                        "qcom_dwc3 DM_HS", qcom);
 499                if (ret) {
 500                        dev_err(qcom->dev, "dm_hs_phy_irq failed: %d\n", ret);
 501                        return ret;
 502                }
 503                qcom->dm_hs_phy_irq = irq;
 504        }
 505
 506        irq = dwc3_qcom_get_irq(pdev, "ss_phy_irq",
 507                                pdata ? pdata->ss_phy_irq_index : -1);
 508        if (irq > 0) {
 509                irq_set_status_flags(irq, IRQ_NOAUTOEN);
 510                ret = devm_request_threaded_irq(qcom->dev, irq, NULL,
 511                                        qcom_dwc3_resume_irq,
 512                                        IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
 513                                        "qcom_dwc3 SS", qcom);
 514                if (ret) {
 515                        dev_err(qcom->dev, "ss_phy_irq failed: %d\n", ret);
 516                        return ret;
 517                }
 518                qcom->ss_phy_irq = irq;
 519        }
 520
 521        return 0;
 522}
 523
 524static int dwc3_qcom_clk_init(struct dwc3_qcom *qcom, int count)
 525{
 526        struct device           *dev = qcom->dev;
 527        struct device_node      *np = dev->of_node;
 528        int                     i;
 529
 530        if (!np || !count)
 531                return 0;
 532
 533        if (count < 0)
 534                return count;
 535
 536        qcom->num_clocks = count;
 537
 538        qcom->clks = devm_kcalloc(dev, qcom->num_clocks,
 539                                  sizeof(struct clk *), GFP_KERNEL);
 540        if (!qcom->clks)
 541                return -ENOMEM;
 542
 543        for (i = 0; i < qcom->num_clocks; i++) {
 544                struct clk      *clk;
 545                int             ret;
 546
 547                clk = of_clk_get(np, i);
 548                if (IS_ERR(clk)) {
 549                        while (--i >= 0)
 550                                clk_put(qcom->clks[i]);
 551                        return PTR_ERR(clk);
 552                }
 553
 554                ret = clk_prepare_enable(clk);
 555                if (ret < 0) {
 556                        while (--i >= 0) {
 557                                clk_disable_unprepare(qcom->clks[i]);
 558                                clk_put(qcom->clks[i]);
 559                        }
 560                        clk_put(clk);
 561
 562                        return ret;
 563                }
 564
 565                qcom->clks[i] = clk;
 566        }
 567
 568        return 0;
 569}
 570
 571static const struct property_entry dwc3_qcom_acpi_properties[] = {
 572        PROPERTY_ENTRY_STRING("dr_mode", "host"),
 573        {}
 574};
 575
 576static const struct software_node dwc3_qcom_swnode = {
 577        .properties = dwc3_qcom_acpi_properties,
 578};
 579
 580static int dwc3_qcom_acpi_register_core(struct platform_device *pdev)
 581{
 582        struct dwc3_qcom        *qcom = platform_get_drvdata(pdev);
 583        struct device           *dev = &pdev->dev;
 584        struct resource         *res, *child_res = NULL;
 585        struct platform_device  *pdev_irq = qcom->urs_usb ? qcom->urs_usb :
 586                                                            pdev;
 587        int                     irq;
 588        int                     ret;
 589
 590        qcom->dwc3 = platform_device_alloc("dwc3", PLATFORM_DEVID_AUTO);
 591        if (!qcom->dwc3)
 592                return -ENOMEM;
 593
 594        qcom->dwc3->dev.parent = dev;
 595        qcom->dwc3->dev.type = dev->type;
 596        qcom->dwc3->dev.dma_mask = dev->dma_mask;
 597        qcom->dwc3->dev.dma_parms = dev->dma_parms;
 598        qcom->dwc3->dev.coherent_dma_mask = dev->coherent_dma_mask;
 599
 600        child_res = kcalloc(2, sizeof(*child_res), GFP_KERNEL);
 601        if (!child_res)
 602                return -ENOMEM;
 603
 604        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 605        if (!res) {
 606                dev_err(&pdev->dev, "failed to get memory resource\n");
 607                ret = -ENODEV;
 608                goto out;
 609        }
 610
 611        child_res[0].flags = res->flags;
 612        child_res[0].start = res->start;
 613        child_res[0].end = child_res[0].start +
 614                qcom->acpi_pdata->dwc3_core_base_size;
 615
 616        irq = platform_get_irq(pdev_irq, 0);
 617        if (irq < 0) {
 618                ret = irq;
 619                goto out;
 620        }
 621        child_res[1].flags = IORESOURCE_IRQ;
 622        child_res[1].start = child_res[1].end = irq;
 623
 624        ret = platform_device_add_resources(qcom->dwc3, child_res, 2);
 625        if (ret) {
 626                dev_err(&pdev->dev, "failed to add resources\n");
 627                goto out;
 628        }
 629
 630        ret = device_add_software_node(&qcom->dwc3->dev, &dwc3_qcom_swnode);
 631        if (ret < 0) {
 632                dev_err(&pdev->dev, "failed to add properties\n");
 633                goto out;
 634        }
 635
 636        ret = platform_device_add(qcom->dwc3);
 637        if (ret) {
 638                dev_err(&pdev->dev, "failed to add device\n");
 639                device_remove_software_node(&qcom->dwc3->dev);
 640        }
 641
 642out:
 643        kfree(child_res);
 644        return ret;
 645}
 646
 647static int dwc3_qcom_of_register_core(struct platform_device *pdev)
 648{
 649        struct dwc3_qcom        *qcom = platform_get_drvdata(pdev);
 650        struct device_node      *np = pdev->dev.of_node, *dwc3_np;
 651        struct device           *dev = &pdev->dev;
 652        int                     ret;
 653
 654        dwc3_np = of_get_compatible_child(np, "snps,dwc3");
 655        if (!dwc3_np) {
 656                dev_err(dev, "failed to find dwc3 core child\n");
 657                return -ENODEV;
 658        }
 659
 660        ret = of_platform_populate(np, NULL, NULL, dev);
 661        if (ret) {
 662                dev_err(dev, "failed to register dwc3 core - %d\n", ret);
 663                goto node_put;
 664        }
 665
 666        qcom->dwc3 = of_find_device_by_node(dwc3_np);
 667        if (!qcom->dwc3) {
 668                ret = -ENODEV;
 669                dev_err(dev, "failed to get dwc3 platform device\n");
 670        }
 671
 672node_put:
 673        of_node_put(dwc3_np);
 674
 675        return ret;
 676}
 677
 678static struct platform_device *
 679dwc3_qcom_create_urs_usb_platdev(struct device *dev)
 680{
 681        struct fwnode_handle *fwh;
 682        struct acpi_device *adev;
 683        char name[8];
 684        int ret;
 685        int id;
 686
 687        /* Figure out device id */
 688        ret = sscanf(fwnode_get_name(dev->fwnode), "URS%d", &id);
 689        if (!ret)
 690                return NULL;
 691
 692        /* Find the child using name */
 693        snprintf(name, sizeof(name), "USB%d", id);
 694        fwh = fwnode_get_named_child_node(dev->fwnode, name);
 695        if (!fwh)
 696                return NULL;
 697
 698        adev = to_acpi_device_node(fwh);
 699        if (!adev)
 700                return NULL;
 701
 702        return acpi_create_platform_device(adev, NULL);
 703}
 704
 705static int dwc3_qcom_probe(struct platform_device *pdev)
 706{
 707        struct device_node      *np = pdev->dev.of_node;
 708        struct device           *dev = &pdev->dev;
 709        struct dwc3_qcom        *qcom;
 710        struct resource         *res, *parent_res = NULL;
 711        int                     ret, i;
 712        bool                    ignore_pipe_clk;
 713
 714        qcom = devm_kzalloc(&pdev->dev, sizeof(*qcom), GFP_KERNEL);
 715        if (!qcom)
 716                return -ENOMEM;
 717
 718        platform_set_drvdata(pdev, qcom);
 719        qcom->dev = &pdev->dev;
 720
 721        if (has_acpi_companion(dev)) {
 722                qcom->acpi_pdata = acpi_device_get_match_data(dev);
 723                if (!qcom->acpi_pdata) {
 724                        dev_err(&pdev->dev, "no supporting ACPI device data\n");
 725                        return -EINVAL;
 726                }
 727        }
 728
 729        qcom->resets = devm_reset_control_array_get_optional_exclusive(dev);
 730        if (IS_ERR(qcom->resets)) {
 731                ret = PTR_ERR(qcom->resets);
 732                dev_err(&pdev->dev, "failed to get resets, err=%d\n", ret);
 733                return ret;
 734        }
 735
 736        ret = reset_control_assert(qcom->resets);
 737        if (ret) {
 738                dev_err(&pdev->dev, "failed to assert resets, err=%d\n", ret);
 739                return ret;
 740        }
 741
 742        usleep_range(10, 1000);
 743
 744        ret = reset_control_deassert(qcom->resets);
 745        if (ret) {
 746                dev_err(&pdev->dev, "failed to deassert resets, err=%d\n", ret);
 747                goto reset_assert;
 748        }
 749
 750        ret = dwc3_qcom_clk_init(qcom, of_clk_get_parent_count(np));
 751        if (ret) {
 752                dev_err(dev, "failed to get clocks\n");
 753                goto reset_assert;
 754        }
 755
 756        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 757
 758        if (np) {
 759                parent_res = res;
 760        } else {
 761                parent_res = kmemdup(res, sizeof(struct resource), GFP_KERNEL);
 762                if (!parent_res)
 763                        return -ENOMEM;
 764
 765                parent_res->start = res->start +
 766                        qcom->acpi_pdata->qscratch_base_offset;
 767                parent_res->end = parent_res->start +
 768                        qcom->acpi_pdata->qscratch_base_size;
 769
 770                if (qcom->acpi_pdata->is_urs) {
 771                        qcom->urs_usb = dwc3_qcom_create_urs_usb_platdev(dev);
 772                        if (!qcom->urs_usb) {
 773                                dev_err(dev, "failed to create URS USB platdev\n");
 774                                return -ENODEV;
 775                        }
 776                }
 777        }
 778
 779        qcom->qscratch_base = devm_ioremap_resource(dev, parent_res);
 780        if (IS_ERR(qcom->qscratch_base)) {
 781                ret = PTR_ERR(qcom->qscratch_base);
 782                goto clk_disable;
 783        }
 784
 785        ret = dwc3_qcom_setup_irq(pdev);
 786        if (ret) {
 787                dev_err(dev, "failed to setup IRQs, err=%d\n", ret);
 788                goto clk_disable;
 789        }
 790
 791        /*
 792         * Disable pipe_clk requirement if specified. Used when dwc3
 793         * operates without SSPHY and only HS/FS/LS modes are supported.
 794         */
 795        ignore_pipe_clk = device_property_read_bool(dev,
 796                                "qcom,select-utmi-as-pipe-clk");
 797        if (ignore_pipe_clk)
 798                dwc3_qcom_select_utmi_clk(qcom);
 799
 800        if (np)
 801                ret = dwc3_qcom_of_register_core(pdev);
 802        else
 803                ret = dwc3_qcom_acpi_register_core(pdev);
 804
 805        if (ret) {
 806                dev_err(dev, "failed to register DWC3 Core, err=%d\n", ret);
 807                goto depopulate;
 808        }
 809
 810        ret = dwc3_qcom_interconnect_init(qcom);
 811        if (ret)
 812                goto depopulate;
 813
 814        qcom->mode = usb_get_dr_mode(&qcom->dwc3->dev);
 815
 816        /* enable vbus override for device mode */
 817        if (qcom->mode == USB_DR_MODE_PERIPHERAL)
 818                dwc3_qcom_vbus_overrride_enable(qcom, true);
 819
 820        /* register extcon to override sw_vbus on Vbus change later */
 821        ret = dwc3_qcom_register_extcon(qcom);
 822        if (ret)
 823                goto interconnect_exit;
 824
 825        device_init_wakeup(&pdev->dev, 1);
 826        qcom->is_suspended = false;
 827        pm_runtime_set_active(dev);
 828        pm_runtime_enable(dev);
 829        pm_runtime_forbid(dev);
 830
 831        return 0;
 832
 833interconnect_exit:
 834        dwc3_qcom_interconnect_exit(qcom);
 835depopulate:
 836        if (np)
 837                of_platform_depopulate(&pdev->dev);
 838        else
 839                platform_device_put(pdev);
 840clk_disable:
 841        for (i = qcom->num_clocks - 1; i >= 0; i--) {
 842                clk_disable_unprepare(qcom->clks[i]);
 843                clk_put(qcom->clks[i]);
 844        }
 845reset_assert:
 846        reset_control_assert(qcom->resets);
 847
 848        return ret;
 849}
 850
 851static int dwc3_qcom_remove(struct platform_device *pdev)
 852{
 853        struct dwc3_qcom *qcom = platform_get_drvdata(pdev);
 854        struct device *dev = &pdev->dev;
 855        int i;
 856
 857        device_remove_software_node(&qcom->dwc3->dev);
 858        of_platform_depopulate(dev);
 859
 860        for (i = qcom->num_clocks - 1; i >= 0; i--) {
 861                clk_disable_unprepare(qcom->clks[i]);
 862                clk_put(qcom->clks[i]);
 863        }
 864        qcom->num_clocks = 0;
 865
 866        dwc3_qcom_interconnect_exit(qcom);
 867        reset_control_assert(qcom->resets);
 868
 869        pm_runtime_allow(dev);
 870        pm_runtime_disable(dev);
 871
 872        return 0;
 873}
 874
 875static int __maybe_unused dwc3_qcom_pm_suspend(struct device *dev)
 876{
 877        struct dwc3_qcom *qcom = dev_get_drvdata(dev);
 878        int ret = 0;
 879
 880        ret = dwc3_qcom_suspend(qcom);
 881        if (!ret)
 882                qcom->pm_suspended = true;
 883
 884        return ret;
 885}
 886
 887static int __maybe_unused dwc3_qcom_pm_resume(struct device *dev)
 888{
 889        struct dwc3_qcom *qcom = dev_get_drvdata(dev);
 890        int ret;
 891
 892        ret = dwc3_qcom_resume(qcom);
 893        if (!ret)
 894                qcom->pm_suspended = false;
 895
 896        return ret;
 897}
 898
 899static int __maybe_unused dwc3_qcom_runtime_suspend(struct device *dev)
 900{
 901        struct dwc3_qcom *qcom = dev_get_drvdata(dev);
 902
 903        return dwc3_qcom_suspend(qcom);
 904}
 905
 906static int __maybe_unused dwc3_qcom_runtime_resume(struct device *dev)
 907{
 908        struct dwc3_qcom *qcom = dev_get_drvdata(dev);
 909
 910        return dwc3_qcom_resume(qcom);
 911}
 912
 913static const struct dev_pm_ops dwc3_qcom_dev_pm_ops = {
 914        SET_SYSTEM_SLEEP_PM_OPS(dwc3_qcom_pm_suspend, dwc3_qcom_pm_resume)
 915        SET_RUNTIME_PM_OPS(dwc3_qcom_runtime_suspend, dwc3_qcom_runtime_resume,
 916                           NULL)
 917};
 918
 919static const struct of_device_id dwc3_qcom_of_match[] = {
 920        { .compatible = "qcom,dwc3" },
 921        { .compatible = "qcom,msm8996-dwc3" },
 922        { .compatible = "qcom,msm8998-dwc3" },
 923        { .compatible = "qcom,sdm845-dwc3" },
 924        { }
 925};
 926MODULE_DEVICE_TABLE(of, dwc3_qcom_of_match);
 927
 928#ifdef CONFIG_ACPI
 929static const struct dwc3_acpi_pdata sdm845_acpi_pdata = {
 930        .qscratch_base_offset = SDM845_QSCRATCH_BASE_OFFSET,
 931        .qscratch_base_size = SDM845_QSCRATCH_SIZE,
 932        .dwc3_core_base_size = SDM845_DWC3_CORE_SIZE,
 933        .hs_phy_irq_index = 1,
 934        .dp_hs_phy_irq_index = 4,
 935        .dm_hs_phy_irq_index = 3,
 936        .ss_phy_irq_index = 2
 937};
 938
 939static const struct dwc3_acpi_pdata sdm845_acpi_urs_pdata = {
 940        .qscratch_base_offset = SDM845_QSCRATCH_BASE_OFFSET,
 941        .qscratch_base_size = SDM845_QSCRATCH_SIZE,
 942        .dwc3_core_base_size = SDM845_DWC3_CORE_SIZE,
 943        .hs_phy_irq_index = 1,
 944        .dp_hs_phy_irq_index = 4,
 945        .dm_hs_phy_irq_index = 3,
 946        .ss_phy_irq_index = 2,
 947        .is_urs = true,
 948};
 949
 950static const struct acpi_device_id dwc3_qcom_acpi_match[] = {
 951        { "QCOM2430", (unsigned long)&sdm845_acpi_pdata },
 952        { "QCOM0304", (unsigned long)&sdm845_acpi_urs_pdata },
 953        { "QCOM0497", (unsigned long)&sdm845_acpi_urs_pdata },
 954        { "QCOM04A6", (unsigned long)&sdm845_acpi_pdata },
 955        { },
 956};
 957MODULE_DEVICE_TABLE(acpi, dwc3_qcom_acpi_match);
 958#endif
 959
 960static struct platform_driver dwc3_qcom_driver = {
 961        .probe          = dwc3_qcom_probe,
 962        .remove         = dwc3_qcom_remove,
 963        .driver         = {
 964                .name   = "dwc3-qcom",
 965                .pm     = &dwc3_qcom_dev_pm_ops,
 966                .of_match_table = dwc3_qcom_of_match,
 967                .acpi_match_table = ACPI_PTR(dwc3_qcom_acpi_match),
 968        },
 969};
 970
 971module_platform_driver(dwc3_qcom_driver);
 972
 973MODULE_LICENSE("GPL v2");
 974MODULE_DESCRIPTION("DesignWare DWC3 QCOM Glue Driver");
 975