linux/drivers/usb/dwc2/platform.c
<<
>>
Prefs
   1/*
   2 * platform.c - DesignWare HS OTG Controller platform driver
   3 *
   4 * Copyright (C) Matthijs Kooijman <matthijs@stdin.nl>
   5 *
   6 * Redistribution and use in source and binary forms, with or without
   7 * modification, are permitted provided that the following conditions
   8 * are met:
   9 * 1. Redistributions of source code must retain the above copyright
  10 *    notice, this list of conditions, and the following disclaimer,
  11 *    without modification.
  12 * 2. Redistributions in binary form must reproduce the above copyright
  13 *    notice, this list of conditions and the following disclaimer in the
  14 *    documentation and/or other materials provided with the distribution.
  15 * 3. The names of the above-listed copyright holders may not be used
  16 *    to endorse or promote products derived from this software without
  17 *    specific prior written permission.
  18 *
  19 * ALTERNATIVELY, this software may be distributed under the terms of the
  20 * GNU General Public License ("GPL") as published by the Free Software
  21 * Foundation; either version 2 of the License, or (at your option) any
  22 * later version.
  23 *
  24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  25 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  26 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  27 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  28 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  29 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  30 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  31 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  32 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  33 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  34 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  35 */
  36
  37#include <linux/kernel.h>
  38#include <linux/module.h>
  39#include <linux/slab.h>
  40#include <linux/clk.h>
  41#include <linux/device.h>
  42#include <linux/dma-mapping.h>
  43#include <linux/of_device.h>
  44#include <linux/mutex.h>
  45#include <linux/platform_device.h>
  46#include <linux/phy/phy.h>
  47#include <linux/platform_data/s3c-hsotg.h>
  48#include <linux/reset.h>
  49
  50#include <linux/usb/of.h>
  51
  52#include "core.h"
  53#include "hcd.h"
  54#include "debug.h"
  55
  56static const char dwc2_driver_name[] = "dwc2";
  57
  58/*
  59 * Check the dr_mode against the module configuration and hardware
  60 * capabilities.
  61 *
  62 * The hardware, module, and dr_mode, can each be set to host, device,
  63 * or otg. Check that all these values are compatible and adjust the
  64 * value of dr_mode if possible.
  65 *
  66 *                      actual
  67 *    HW  MOD dr_mode   dr_mode
  68 *  ------------------------------
  69 *   HST  HST  any    :  HST
  70 *   HST  DEV  any    :  ---
  71 *   HST  OTG  any    :  HST
  72 *
  73 *   DEV  HST  any    :  ---
  74 *   DEV  DEV  any    :  DEV
  75 *   DEV  OTG  any    :  DEV
  76 *
  77 *   OTG  HST  any    :  HST
  78 *   OTG  DEV  any    :  DEV
  79 *   OTG  OTG  any    :  dr_mode
  80 */
  81static int dwc2_get_dr_mode(struct dwc2_hsotg *hsotg)
  82{
  83        enum usb_dr_mode mode;
  84
  85        hsotg->dr_mode = usb_get_dr_mode(hsotg->dev);
  86        if (hsotg->dr_mode == USB_DR_MODE_UNKNOWN)
  87                hsotg->dr_mode = USB_DR_MODE_OTG;
  88
  89        mode = hsotg->dr_mode;
  90
  91        if (dwc2_hw_is_device(hsotg)) {
  92                if (IS_ENABLED(CONFIG_USB_DWC2_HOST)) {
  93                        dev_err(hsotg->dev,
  94                                "Controller does not support host mode.\n");
  95                        return -EINVAL;
  96                }
  97                mode = USB_DR_MODE_PERIPHERAL;
  98        } else if (dwc2_hw_is_host(hsotg)) {
  99                if (IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL)) {
 100                        dev_err(hsotg->dev,
 101                                "Controller does not support device mode.\n");
 102                        return -EINVAL;
 103                }
 104                mode = USB_DR_MODE_HOST;
 105        } else {
 106                if (IS_ENABLED(CONFIG_USB_DWC2_HOST))
 107                        mode = USB_DR_MODE_HOST;
 108                else if (IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL))
 109                        mode = USB_DR_MODE_PERIPHERAL;
 110        }
 111
 112        if (mode != hsotg->dr_mode) {
 113                dev_warn(hsotg->dev,
 114                         "Configuration mismatch. dr_mode forced to %s\n",
 115                        mode == USB_DR_MODE_HOST ? "host" : "device");
 116
 117                hsotg->dr_mode = mode;
 118        }
 119
 120        return 0;
 121}
 122
 123static int __dwc2_lowlevel_hw_enable(struct dwc2_hsotg *hsotg)
 124{
 125        struct platform_device *pdev = to_platform_device(hsotg->dev);
 126        int ret;
 127
 128        ret = regulator_bulk_enable(ARRAY_SIZE(hsotg->supplies),
 129                                    hsotg->supplies);
 130        if (ret)
 131                return ret;
 132
 133        if (hsotg->clk) {
 134                ret = clk_prepare_enable(hsotg->clk);
 135                if (ret)
 136                        return ret;
 137        }
 138
 139        if (hsotg->uphy) {
 140                ret = usb_phy_init(hsotg->uphy);
 141        } else if (hsotg->plat && hsotg->plat->phy_init) {
 142                ret = hsotg->plat->phy_init(pdev, hsotg->plat->phy_type);
 143        } else {
 144                ret = phy_power_on(hsotg->phy);
 145                if (ret == 0)
 146                        ret = phy_init(hsotg->phy);
 147        }
 148
 149        return ret;
 150}
 151
 152/**
 153 * dwc2_lowlevel_hw_enable - enable platform lowlevel hw resources
 154 * @hsotg: The driver state
 155 *
 156 * A wrapper for platform code responsible for controlling
 157 * low-level USB platform resources (phy, clock, regulators)
 158 */
 159int dwc2_lowlevel_hw_enable(struct dwc2_hsotg *hsotg)
 160{
 161        int ret = __dwc2_lowlevel_hw_enable(hsotg);
 162
 163        if (ret == 0)
 164                hsotg->ll_hw_enabled = true;
 165        return ret;
 166}
 167
 168static int __dwc2_lowlevel_hw_disable(struct dwc2_hsotg *hsotg)
 169{
 170        struct platform_device *pdev = to_platform_device(hsotg->dev);
 171        int ret = 0;
 172
 173        if (hsotg->uphy) {
 174                usb_phy_shutdown(hsotg->uphy);
 175        } else if (hsotg->plat && hsotg->plat->phy_exit) {
 176                ret = hsotg->plat->phy_exit(pdev, hsotg->plat->phy_type);
 177        } else {
 178                ret = phy_exit(hsotg->phy);
 179                if (ret == 0)
 180                        ret = phy_power_off(hsotg->phy);
 181        }
 182        if (ret)
 183                return ret;
 184
 185        if (hsotg->clk)
 186                clk_disable_unprepare(hsotg->clk);
 187
 188        ret = regulator_bulk_disable(ARRAY_SIZE(hsotg->supplies),
 189                                     hsotg->supplies);
 190
 191        return ret;
 192}
 193
 194/**
 195 * dwc2_lowlevel_hw_disable - disable platform lowlevel hw resources
 196 * @hsotg: The driver state
 197 *
 198 * A wrapper for platform code responsible for controlling
 199 * low-level USB platform resources (phy, clock, regulators)
 200 */
 201int dwc2_lowlevel_hw_disable(struct dwc2_hsotg *hsotg)
 202{
 203        int ret = __dwc2_lowlevel_hw_disable(hsotg);
 204
 205        if (ret == 0)
 206                hsotg->ll_hw_enabled = false;
 207        return ret;
 208}
 209
 210static int dwc2_lowlevel_hw_init(struct dwc2_hsotg *hsotg)
 211{
 212        int i, ret;
 213
 214        hsotg->reset = devm_reset_control_get_optional(hsotg->dev, "dwc2");
 215        if (IS_ERR(hsotg->reset)) {
 216                ret = PTR_ERR(hsotg->reset);
 217                dev_err(hsotg->dev, "error getting reset control %d\n", ret);
 218                return ret;
 219        }
 220
 221        reset_control_deassert(hsotg->reset);
 222
 223        /* Set default UTMI width */
 224        hsotg->phyif = GUSBCFG_PHYIF16;
 225
 226        /*
 227         * Attempt to find a generic PHY, then look for an old style
 228         * USB PHY and then fall back to pdata
 229         */
 230        hsotg->phy = devm_phy_get(hsotg->dev, "usb2-phy");
 231        if (IS_ERR(hsotg->phy)) {
 232                ret = PTR_ERR(hsotg->phy);
 233                switch (ret) {
 234                case -ENODEV:
 235                case -ENOSYS:
 236                        hsotg->phy = NULL;
 237                        break;
 238                case -EPROBE_DEFER:
 239                        return ret;
 240                default:
 241                        dev_err(hsotg->dev, "error getting phy %d\n", ret);
 242                        return ret;
 243                }
 244        }
 245
 246        if (!hsotg->phy) {
 247                hsotg->uphy = devm_usb_get_phy(hsotg->dev, USB_PHY_TYPE_USB2);
 248                if (IS_ERR(hsotg->uphy)) {
 249                        ret = PTR_ERR(hsotg->uphy);
 250                        switch (ret) {
 251                        case -ENODEV:
 252                        case -ENXIO:
 253                                hsotg->uphy = NULL;
 254                                break;
 255                        case -EPROBE_DEFER:
 256                                return ret;
 257                        default:
 258                                dev_err(hsotg->dev, "error getting usb phy %d\n",
 259                                        ret);
 260                                return ret;
 261                        }
 262                }
 263        }
 264
 265        hsotg->plat = dev_get_platdata(hsotg->dev);
 266
 267        if (hsotg->phy) {
 268                /*
 269                 * If using the generic PHY framework, check if the PHY bus
 270                 * width is 8-bit and set the phyif appropriately.
 271                 */
 272                if (phy_get_bus_width(hsotg->phy) == 8)
 273                        hsotg->phyif = GUSBCFG_PHYIF8;
 274        }
 275
 276        /* Clock */
 277        hsotg->clk = devm_clk_get(hsotg->dev, "otg");
 278        if (IS_ERR(hsotg->clk)) {
 279                hsotg->clk = NULL;
 280                dev_dbg(hsotg->dev, "cannot get otg clock\n");
 281        }
 282
 283        /* Regulators */
 284        for (i = 0; i < ARRAY_SIZE(hsotg->supplies); i++)
 285                hsotg->supplies[i].supply = dwc2_hsotg_supply_names[i];
 286
 287        ret = devm_regulator_bulk_get(hsotg->dev, ARRAY_SIZE(hsotg->supplies),
 288                                      hsotg->supplies);
 289        if (ret) {
 290                dev_err(hsotg->dev, "failed to request supplies: %d\n", ret);
 291                return ret;
 292        }
 293        return 0;
 294}
 295
 296/**
 297 * dwc2_driver_remove() - Called when the DWC_otg core is unregistered with the
 298 * DWC_otg driver
 299 *
 300 * @dev: Platform device
 301 *
 302 * This routine is called, for example, when the rmmod command is executed. The
 303 * device may or may not be electrically present. If it is present, the driver
 304 * stops device processing. Any resources used on behalf of this device are
 305 * freed.
 306 */
 307static int dwc2_driver_remove(struct platform_device *dev)
 308{
 309        struct dwc2_hsotg *hsotg = platform_get_drvdata(dev);
 310
 311        dwc2_debugfs_exit(hsotg);
 312        if (hsotg->hcd_enabled)
 313                dwc2_hcd_remove(hsotg);
 314        if (hsotg->gadget_enabled)
 315                dwc2_hsotg_remove(hsotg);
 316
 317        if (hsotg->ll_hw_enabled)
 318                dwc2_lowlevel_hw_disable(hsotg);
 319
 320        reset_control_assert(hsotg->reset);
 321
 322        return 0;
 323}
 324
 325/**
 326 * dwc2_driver_shutdown() - Called on device shutdown
 327 *
 328 * @dev: Platform device
 329 *
 330 * In specific conditions (involving usb hubs) dwc2 devices can create a
 331 * lot of interrupts, even to the point of overwhelming devices running
 332 * at low frequencies. Some devices need to do special clock handling
 333 * at shutdown-time which may bring the system clock below the threshold
 334 * of being able to handle the dwc2 interrupts. Disabling dwc2-irqs
 335 * prevents reboots/poweroffs from getting stuck in such cases.
 336 */
 337static void dwc2_driver_shutdown(struct platform_device *dev)
 338{
 339        struct dwc2_hsotg *hsotg = platform_get_drvdata(dev);
 340
 341        disable_irq(hsotg->irq);
 342}
 343
 344/**
 345 * dwc2_driver_probe() - Called when the DWC_otg core is bound to the DWC_otg
 346 * driver
 347 *
 348 * @dev: Platform device
 349 *
 350 * This routine creates the driver components required to control the device
 351 * (core, HCD, and PCD) and initializes the device. The driver components are
 352 * stored in a dwc2_hsotg structure. A reference to the dwc2_hsotg is saved
 353 * in the device private data. This allows the driver to access the dwc2_hsotg
 354 * structure on subsequent calls to driver methods for this device.
 355 */
 356static int dwc2_driver_probe(struct platform_device *dev)
 357{
 358        struct dwc2_hsotg *hsotg;
 359        struct resource *res;
 360        int retval;
 361
 362        hsotg = devm_kzalloc(&dev->dev, sizeof(*hsotg), GFP_KERNEL);
 363        if (!hsotg)
 364                return -ENOMEM;
 365
 366        hsotg->dev = &dev->dev;
 367
 368        /*
 369         * Use reasonable defaults so platforms don't have to provide these.
 370         */
 371        if (!dev->dev.dma_mask)
 372                dev->dev.dma_mask = &dev->dev.coherent_dma_mask;
 373        retval = dma_set_coherent_mask(&dev->dev, DMA_BIT_MASK(32));
 374        if (retval)
 375                return retval;
 376
 377        res = platform_get_resource(dev, IORESOURCE_MEM, 0);
 378        hsotg->regs = devm_ioremap_resource(&dev->dev, res);
 379        if (IS_ERR(hsotg->regs))
 380                return PTR_ERR(hsotg->regs);
 381
 382        dev_dbg(&dev->dev, "mapped PA %08lx to VA %p\n",
 383                (unsigned long)res->start, hsotg->regs);
 384
 385        retval = dwc2_lowlevel_hw_init(hsotg);
 386        if (retval)
 387                return retval;
 388
 389        spin_lock_init(&hsotg->lock);
 390
 391        hsotg->irq = platform_get_irq(dev, 0);
 392        if (hsotg->irq < 0) {
 393                dev_err(&dev->dev, "missing IRQ resource\n");
 394                return hsotg->irq;
 395        }
 396
 397        dev_dbg(hsotg->dev, "registering common handler for irq%d\n",
 398                hsotg->irq);
 399        retval = devm_request_irq(hsotg->dev, hsotg->irq,
 400                                  dwc2_handle_common_intr, IRQF_SHARED,
 401                                  dev_name(hsotg->dev), hsotg);
 402        if (retval)
 403                return retval;
 404
 405        retval = dwc2_lowlevel_hw_enable(hsotg);
 406        if (retval)
 407                return retval;
 408
 409        retval = dwc2_get_dr_mode(hsotg);
 410        if (retval)
 411                goto error;
 412
 413        /*
 414         * Reset before dwc2_get_hwparams() then it could get power-on real
 415         * reset value form registers.
 416         */
 417        dwc2_core_reset_and_force_dr_mode(hsotg);
 418
 419        /* Detect config values from hardware */
 420        retval = dwc2_get_hwparams(hsotg);
 421        if (retval)
 422                goto error;
 423
 424        dwc2_force_dr_mode(hsotg);
 425
 426        retval = dwc2_init_params(hsotg);
 427        if (retval)
 428                goto error;
 429
 430        if (hsotg->dr_mode != USB_DR_MODE_HOST) {
 431                retval = dwc2_gadget_init(hsotg, hsotg->irq);
 432                if (retval)
 433                        goto error;
 434                hsotg->gadget_enabled = 1;
 435        }
 436
 437        if (hsotg->dr_mode != USB_DR_MODE_PERIPHERAL) {
 438                retval = dwc2_hcd_init(hsotg);
 439                if (retval) {
 440                        if (hsotg->gadget_enabled)
 441                                dwc2_hsotg_remove(hsotg);
 442                        goto error;
 443                }
 444                hsotg->hcd_enabled = 1;
 445        }
 446
 447        platform_set_drvdata(dev, hsotg);
 448
 449        dwc2_debugfs_init(hsotg);
 450
 451        /* Gadget code manages lowlevel hw on its own */
 452        if (hsotg->dr_mode == USB_DR_MODE_PERIPHERAL)
 453                dwc2_lowlevel_hw_disable(hsotg);
 454
 455        return 0;
 456
 457error:
 458        dwc2_lowlevel_hw_disable(hsotg);
 459        return retval;
 460}
 461
 462static int __maybe_unused dwc2_suspend(struct device *dev)
 463{
 464        struct dwc2_hsotg *dwc2 = dev_get_drvdata(dev);
 465        int ret = 0;
 466
 467        if (dwc2_is_device_mode(dwc2))
 468                dwc2_hsotg_suspend(dwc2);
 469
 470        if (dwc2->ll_hw_enabled)
 471                ret = __dwc2_lowlevel_hw_disable(dwc2);
 472
 473        return ret;
 474}
 475
 476static int __maybe_unused dwc2_resume(struct device *dev)
 477{
 478        struct dwc2_hsotg *dwc2 = dev_get_drvdata(dev);
 479        int ret = 0;
 480
 481        if (dwc2->ll_hw_enabled) {
 482                ret = __dwc2_lowlevel_hw_enable(dwc2);
 483                if (ret)
 484                        return ret;
 485        }
 486
 487        if (dwc2_is_device_mode(dwc2))
 488                ret = dwc2_hsotg_resume(dwc2);
 489
 490        return ret;
 491}
 492
 493static const struct dev_pm_ops dwc2_dev_pm_ops = {
 494        SET_SYSTEM_SLEEP_PM_OPS(dwc2_suspend, dwc2_resume)
 495};
 496
 497static struct platform_driver dwc2_platform_driver = {
 498        .driver = {
 499                .name = dwc2_driver_name,
 500                .of_match_table = dwc2_of_match_table,
 501                .pm = &dwc2_dev_pm_ops,
 502        },
 503        .probe = dwc2_driver_probe,
 504        .remove = dwc2_driver_remove,
 505        .shutdown = dwc2_driver_shutdown,
 506};
 507
 508module_platform_driver(dwc2_platform_driver);
 509
 510MODULE_DESCRIPTION("DESIGNWARE HS OTG Platform Glue");
 511MODULE_AUTHOR("Matthijs Kooijman <matthijs@stdin.nl>");
 512MODULE_LICENSE("Dual BSD/GPL");
 513