linux/drivers/usb/cdns3/drd.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Cadence USBSS DRD Driver.
   4 *
   5 * Copyright (C) 2018-2019 Cadence.
   6 * Copyright (C) 2019 Texas Instruments
   7 *
   8 * Author: Pawel Laszczak <pawell@cadence.com>
   9 *         Roger Quadros <rogerq@ti.com>
  10 *
  11 *
  12 */
  13#include <linux/kernel.h>
  14#include <linux/interrupt.h>
  15#include <linux/delay.h>
  16#include <linux/iopoll.h>
  17#include <linux/usb/otg.h>
  18
  19#include "gadget.h"
  20#include "drd.h"
  21#include "core.h"
  22
  23/**
  24 * cdns3_set_mode - change mode of OTG Core
  25 * @cdns: pointer to context structure
  26 * @mode: selected mode from cdns_role
  27 *
  28 * Returns 0 on success otherwise negative errno
  29 */
  30int cdns3_set_mode(struct cdns3 *cdns, enum usb_dr_mode mode)
  31{
  32        int ret = 0;
  33        u32 reg;
  34
  35        switch (mode) {
  36        case USB_DR_MODE_PERIPHERAL:
  37                break;
  38        case USB_DR_MODE_HOST:
  39                break;
  40        case USB_DR_MODE_OTG:
  41                dev_dbg(cdns->dev, "Set controller to OTG mode\n");
  42                if (cdns->version == CDNS3_CONTROLLER_V1) {
  43                        reg = readl(&cdns->otg_v1_regs->override);
  44                        reg |= OVERRIDE_IDPULLUP;
  45                        writel(reg, &cdns->otg_v1_regs->override);
  46                } else {
  47                        reg = readl(&cdns->otg_v0_regs->ctrl1);
  48                        reg |= OVERRIDE_IDPULLUP_V0;
  49                        writel(reg, &cdns->otg_v0_regs->ctrl1);
  50                }
  51
  52                /*
  53                 * Hardware specification says: "ID_VALUE must be valid within
  54                 * 50ms after idpullup is set to '1" so driver must wait
  55                 * 50ms before reading this pin.
  56                 */
  57                usleep_range(50000, 60000);
  58                break;
  59        default:
  60                dev_err(cdns->dev, "Unsupported mode of operation %d\n", mode);
  61                return -EINVAL;
  62        }
  63
  64        return ret;
  65}
  66
  67int cdns3_get_id(struct cdns3 *cdns)
  68{
  69        int id;
  70
  71        id = readl(&cdns->otg_regs->sts) & OTGSTS_ID_VALUE;
  72        dev_dbg(cdns->dev, "OTG ID: %d", id);
  73
  74        return id;
  75}
  76
  77int cdns3_get_vbus(struct cdns3 *cdns)
  78{
  79        int vbus;
  80
  81        vbus = !!(readl(&cdns->otg_regs->sts) & OTGSTS_VBUS_VALID);
  82        dev_dbg(cdns->dev, "OTG VBUS: %d", vbus);
  83
  84        return vbus;
  85}
  86
  87int cdns3_is_host(struct cdns3 *cdns)
  88{
  89        if (cdns->dr_mode == USB_DR_MODE_HOST)
  90                return 1;
  91        else if (!cdns3_get_id(cdns))
  92                return 1;
  93
  94        return 0;
  95}
  96
  97int cdns3_is_device(struct cdns3 *cdns)
  98{
  99        if (cdns->dr_mode == USB_DR_MODE_PERIPHERAL)
 100                return 1;
 101        else if (cdns->dr_mode == USB_DR_MODE_OTG)
 102                if (cdns3_get_id(cdns))
 103                        return 1;
 104
 105        return 0;
 106}
 107
 108/**
 109 * cdns3_otg_disable_irq - Disable all OTG interrupts
 110 * @cdns: Pointer to controller context structure
 111 */
 112static void cdns3_otg_disable_irq(struct cdns3 *cdns)
 113{
 114        writel(0, &cdns->otg_regs->ien);
 115}
 116
 117/**
 118 * cdns3_otg_enable_irq - enable id and sess_valid interrupts
 119 * @cdns: Pointer to controller context structure
 120 */
 121static void cdns3_otg_enable_irq(struct cdns3 *cdns)
 122{
 123        writel(OTGIEN_ID_CHANGE_INT | OTGIEN_VBUSVALID_RISE_INT |
 124               OTGIEN_VBUSVALID_FALL_INT, &cdns->otg_regs->ien);
 125}
 126
 127/**
 128 * cdns3_drd_switch_host - start/stop host
 129 * @cdns: Pointer to controller context structure
 130 * @on: 1 for start, 0 for stop
 131 *
 132 * Returns 0 on success otherwise negative errno
 133 */
 134int cdns3_drd_switch_host(struct cdns3 *cdns, int on)
 135{
 136        int ret, val;
 137        u32 reg = OTGCMD_OTG_DIS;
 138
 139        /* switch OTG core */
 140        if (on) {
 141                writel(OTGCMD_HOST_BUS_REQ | reg, &cdns->otg_regs->cmd);
 142
 143                dev_dbg(cdns->dev, "Waiting till Host mode is turned on\n");
 144                ret = readl_poll_timeout_atomic(&cdns->otg_regs->sts, val,
 145                                                val & OTGSTS_XHCI_READY,
 146                                                1, 100000);
 147                if (ret) {
 148                        dev_err(cdns->dev, "timeout waiting for xhci_ready\n");
 149                        return ret;
 150                }
 151        } else {
 152                writel(OTGCMD_HOST_BUS_DROP | OTGCMD_DEV_BUS_DROP |
 153                       OTGCMD_DEV_POWER_OFF | OTGCMD_HOST_POWER_OFF,
 154                       &cdns->otg_regs->cmd);
 155                /* Waiting till H_IDLE state.*/
 156                readl_poll_timeout_atomic(&cdns->otg_regs->state, val,
 157                                          !(val & OTGSTATE_HOST_STATE_MASK),
 158                                          1, 2000000);
 159        }
 160
 161        return 0;
 162}
 163
 164/**
 165 * cdns3_drd_switch_gadget - start/stop gadget
 166 * @cdns: Pointer to controller context structure
 167 * @on: 1 for start, 0 for stop
 168 *
 169 * Returns 0 on success otherwise negative errno
 170 */
 171int cdns3_drd_switch_gadget(struct cdns3 *cdns, int on)
 172{
 173        int ret, val;
 174        u32 reg = OTGCMD_OTG_DIS;
 175
 176        /* switch OTG core */
 177        if (on) {
 178                writel(OTGCMD_DEV_BUS_REQ | reg, &cdns->otg_regs->cmd);
 179
 180                dev_dbg(cdns->dev, "Waiting till Device mode is turned on\n");
 181
 182                ret = readl_poll_timeout_atomic(&cdns->otg_regs->sts, val,
 183                                                val & OTGSTS_DEV_READY,
 184                                                1, 100000);
 185                if (ret) {
 186                        dev_err(cdns->dev, "timeout waiting for dev_ready\n");
 187                        return ret;
 188                }
 189        } else {
 190                /*
 191                 * driver should wait at least 10us after disabling Device
 192                 * before turning-off Device (DEV_BUS_DROP)
 193                 */
 194                usleep_range(20, 30);
 195                writel(OTGCMD_HOST_BUS_DROP | OTGCMD_DEV_BUS_DROP |
 196                       OTGCMD_DEV_POWER_OFF | OTGCMD_HOST_POWER_OFF,
 197                       &cdns->otg_regs->cmd);
 198                /* Waiting till DEV_IDLE state.*/
 199                readl_poll_timeout_atomic(&cdns->otg_regs->state, val,
 200                                          !(val & OTGSTATE_DEV_STATE_MASK),
 201                                          1, 2000000);
 202        }
 203
 204        return 0;
 205}
 206
 207/**
 208 * cdns3_init_otg_mode - initialize drd controller
 209 * @cdns: Pointer to controller context structure
 210 *
 211 * Returns 0 on success otherwise negative errno
 212 */
 213static int cdns3_init_otg_mode(struct cdns3 *cdns)
 214{
 215        int ret = 0;
 216
 217        cdns3_otg_disable_irq(cdns);
 218        /* clear all interrupts */
 219        writel(~0, &cdns->otg_regs->ivect);
 220
 221        ret = cdns3_set_mode(cdns, USB_DR_MODE_OTG);
 222        if (ret)
 223                return ret;
 224
 225        cdns3_otg_enable_irq(cdns);
 226        return ret;
 227}
 228
 229/**
 230 * cdns3_drd_update_mode - initialize mode of operation
 231 * @cdns: Pointer to controller context structure
 232 *
 233 * Returns 0 on success otherwise negative errno
 234 */
 235int cdns3_drd_update_mode(struct cdns3 *cdns)
 236{
 237        int ret = 0;
 238
 239        switch (cdns->dr_mode) {
 240        case USB_DR_MODE_PERIPHERAL:
 241                ret = cdns3_set_mode(cdns, USB_DR_MODE_PERIPHERAL);
 242                break;
 243        case USB_DR_MODE_HOST:
 244                ret = cdns3_set_mode(cdns, USB_DR_MODE_HOST);
 245                break;
 246        case USB_DR_MODE_OTG:
 247                ret = cdns3_init_otg_mode(cdns);
 248                break;
 249        default:
 250                dev_err(cdns->dev, "Unsupported mode of operation %d\n",
 251                        cdns->dr_mode);
 252                return -EINVAL;
 253        }
 254
 255        return ret;
 256}
 257
 258static irqreturn_t cdns3_drd_thread_irq(int irq, void *data)
 259{
 260        struct cdns3 *cdns = data;
 261
 262        cdns3_hw_role_switch(cdns);
 263
 264        return IRQ_HANDLED;
 265}
 266
 267/**
 268 * cdns3_drd_irq - interrupt handler for OTG events
 269 *
 270 * @irq: irq number for cdns3 core device
 271 * @data: structure of cdns3
 272 *
 273 * Returns IRQ_HANDLED or IRQ_NONE
 274 */
 275static irqreturn_t cdns3_drd_irq(int irq, void *data)
 276{
 277        irqreturn_t ret = IRQ_NONE;
 278        struct cdns3 *cdns = data;
 279        u32 reg;
 280
 281        if (cdns->dr_mode != USB_DR_MODE_OTG)
 282                return ret;
 283
 284        reg = readl(&cdns->otg_regs->ivect);
 285
 286        if (!reg)
 287                return ret;
 288
 289        if (reg & OTGIEN_ID_CHANGE_INT) {
 290                dev_dbg(cdns->dev, "OTG IRQ: new ID: %d\n",
 291                        cdns3_get_id(cdns));
 292
 293                ret = IRQ_WAKE_THREAD;
 294        }
 295
 296        if (reg & (OTGIEN_VBUSVALID_RISE_INT | OTGIEN_VBUSVALID_FALL_INT)) {
 297                dev_dbg(cdns->dev, "OTG IRQ: new VBUS: %d\n",
 298                        cdns3_get_vbus(cdns));
 299
 300                ret = IRQ_WAKE_THREAD;
 301        }
 302
 303        writel(~0, &cdns->otg_regs->ivect);
 304        return ret;
 305}
 306
 307int cdns3_drd_init(struct cdns3 *cdns)
 308{
 309        void __iomem *regs;
 310        int ret = 0;
 311        u32 state;
 312
 313        regs = devm_ioremap_resource(cdns->dev, &cdns->otg_res);
 314        if (IS_ERR(regs))
 315                return PTR_ERR(regs);
 316
 317        /* Detection of DRD version. Controller has been released
 318         * in two versions. Both are similar, but they have same changes
 319         * in register maps.
 320         * The first register in old version is command register and it's read
 321         * only, so driver should read 0 from it. On the other hand, in v1
 322         * the first register contains device ID number which is not set to 0.
 323         * Driver uses this fact to detect the proper version of
 324         * controller.
 325         */
 326        cdns->otg_v0_regs = regs;
 327        if (!readl(&cdns->otg_v0_regs->cmd)) {
 328                cdns->version  = CDNS3_CONTROLLER_V0;
 329                cdns->otg_v1_regs = NULL;
 330                cdns->otg_regs = regs;
 331                writel(1, &cdns->otg_v0_regs->simulate);
 332                dev_dbg(cdns->dev, "DRD version v0 (%08x)\n",
 333                         readl(&cdns->otg_v0_regs->version));
 334        } else {
 335                cdns->otg_v0_regs = NULL;
 336                cdns->otg_v1_regs = regs;
 337                cdns->otg_regs = (void *)&cdns->otg_v1_regs->cmd;
 338                cdns->version  = CDNS3_CONTROLLER_V1;
 339                writel(1, &cdns->otg_v1_regs->simulate);
 340                dev_dbg(cdns->dev, "DRD version v1 (ID: %08x, rev: %08x)\n",
 341                         readl(&cdns->otg_v1_regs->did),
 342                         readl(&cdns->otg_v1_regs->rid));
 343        }
 344
 345        state = OTGSTS_STRAP(readl(&cdns->otg_regs->sts));
 346
 347        /* Update dr_mode according to STRAP configuration. */
 348        cdns->dr_mode = USB_DR_MODE_OTG;
 349        if (state == OTGSTS_STRAP_HOST) {
 350                dev_dbg(cdns->dev, "Controller strapped to HOST\n");
 351                cdns->dr_mode = USB_DR_MODE_HOST;
 352        } else if (state == OTGSTS_STRAP_GADGET) {
 353                dev_dbg(cdns->dev, "Controller strapped to PERIPHERAL\n");
 354                cdns->dr_mode = USB_DR_MODE_PERIPHERAL;
 355        }
 356
 357        ret = devm_request_threaded_irq(cdns->dev, cdns->otg_irq,
 358                                        cdns3_drd_irq,
 359                                        cdns3_drd_thread_irq,
 360                                        IRQF_SHARED,
 361                                        dev_name(cdns->dev), cdns);
 362
 363        if (ret) {
 364                dev_err(cdns->dev, "couldn't get otg_irq\n");
 365                return ret;
 366        }
 367
 368        state = readl(&cdns->otg_regs->sts);
 369        if (OTGSTS_OTG_NRDY(state) != 0) {
 370                dev_err(cdns->dev, "Cadence USB3 OTG device not ready\n");
 371                return -ENODEV;
 372        }
 373
 374        return ret;
 375}
 376
 377int cdns3_drd_exit(struct cdns3 *cdns)
 378{
 379        cdns3_otg_disable_irq(cdns);
 380        return 0;
 381}
 382