linux/drivers/usb/host/ehci-exynos.c
<<
>>
Prefs
   1/*
   2 * SAMSUNG EXYNOS USB HOST EHCI Controller
   3 *
   4 * Copyright (C) 2011 Samsung Electronics Co.Ltd
   5 * Author: Jingoo Han <jg1.han@samsung.com>
   6 * Author: Joonyoung Shim <jy0922.shim@samsung.com>
   7 *
   8 * This program is free software; you can redistribute  it and/or modify it
   9 * under  the terms of  the GNU General  Public License as published by the
  10 * Free Software Foundation;  either version 2 of the  License, or (at your
  11 * option) any later version.
  12 *
  13 */
  14
  15#include <linux/clk.h>
  16#include <linux/dma-mapping.h>
  17#include <linux/io.h>
  18#include <linux/kernel.h>
  19#include <linux/module.h>
  20#include <linux/of.h>
  21#include <linux/of_gpio.h>
  22#include <linux/platform_device.h>
  23#include <linux/usb/phy.h>
  24#include <linux/usb/samsung_usb_phy.h>
  25#include <linux/usb.h>
  26#include <linux/usb/hcd.h>
  27#include <linux/usb/otg.h>
  28
  29#include "ehci.h"
  30
  31#define DRIVER_DESC "EHCI EXYNOS driver"
  32
  33#define EHCI_INSNREG00(base)                    (base + 0x90)
  34#define EHCI_INSNREG00_ENA_INCR16               (0x1 << 25)
  35#define EHCI_INSNREG00_ENA_INCR8                (0x1 << 24)
  36#define EHCI_INSNREG00_ENA_INCR4                (0x1 << 23)
  37#define EHCI_INSNREG00_ENA_INCRX_ALIGN          (0x1 << 22)
  38#define EHCI_INSNREG00_ENABLE_DMA_BURST \
  39        (EHCI_INSNREG00_ENA_INCR16 | EHCI_INSNREG00_ENA_INCR8 | \
  40         EHCI_INSNREG00_ENA_INCR4 | EHCI_INSNREG00_ENA_INCRX_ALIGN)
  41
  42static const char hcd_name[] = "ehci-exynos";
  43static struct hc_driver __read_mostly exynos_ehci_hc_driver;
  44
  45struct exynos_ehci_hcd {
  46        struct clk *clk;
  47        struct usb_phy *phy;
  48        struct usb_otg *otg;
  49};
  50
  51#define to_exynos_ehci(hcd) (struct exynos_ehci_hcd *)(hcd_to_ehci(hcd)->priv)
  52
  53static void exynos_setup_vbus_gpio(struct platform_device *pdev)
  54{
  55        struct device *dev = &pdev->dev;
  56        int err;
  57        int gpio;
  58
  59        if (!dev->of_node)
  60                return;
  61
  62        gpio = of_get_named_gpio(dev->of_node, "samsung,vbus-gpio", 0);
  63        if (!gpio_is_valid(gpio))
  64                return;
  65
  66        err = devm_gpio_request_one(dev, gpio, GPIOF_OUT_INIT_HIGH,
  67                                    "ehci_vbus_gpio");
  68        if (err)
  69                dev_err(dev, "can't request ehci vbus gpio %d", gpio);
  70}
  71
  72static int exynos_ehci_probe(struct platform_device *pdev)
  73{
  74        struct exynos_ehci_hcd *exynos_ehci;
  75        struct usb_hcd *hcd;
  76        struct ehci_hcd *ehci;
  77        struct resource *res;
  78        struct usb_phy *phy;
  79        int irq;
  80        int err;
  81
  82        /*
  83         * Right now device-tree probed devices don't get dma_mask set.
  84         * Since shared usb code relies on it, set it here for now.
  85         * Once we move to full device tree support this will vanish off.
  86         */
  87        err = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
  88        if (err)
  89                return err;
  90
  91        exynos_setup_vbus_gpio(pdev);
  92
  93        hcd = usb_create_hcd(&exynos_ehci_hc_driver,
  94                             &pdev->dev, dev_name(&pdev->dev));
  95        if (!hcd) {
  96                dev_err(&pdev->dev, "Unable to create HCD\n");
  97                return -ENOMEM;
  98        }
  99        exynos_ehci = to_exynos_ehci(hcd);
 100
 101        if (of_device_is_compatible(pdev->dev.of_node,
 102                                        "samsung,exynos5440-ehci"))
 103                goto skip_phy;
 104
 105        phy = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2);
 106        if (IS_ERR(phy)) {
 107                usb_put_hcd(hcd);
 108                dev_warn(&pdev->dev, "no platform data or transceiver defined\n");
 109                return -EPROBE_DEFER;
 110        } else {
 111                exynos_ehci->phy = phy;
 112                exynos_ehci->otg = phy->otg;
 113        }
 114
 115skip_phy:
 116
 117        exynos_ehci->clk = devm_clk_get(&pdev->dev, "usbhost");
 118
 119        if (IS_ERR(exynos_ehci->clk)) {
 120                dev_err(&pdev->dev, "Failed to get usbhost clock\n");
 121                err = PTR_ERR(exynos_ehci->clk);
 122                goto fail_clk;
 123        }
 124
 125        err = clk_prepare_enable(exynos_ehci->clk);
 126        if (err)
 127                goto fail_clk;
 128
 129        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 130        if (!res) {
 131                dev_err(&pdev->dev, "Failed to get I/O memory\n");
 132                err = -ENXIO;
 133                goto fail_io;
 134        }
 135
 136        hcd->rsrc_start = res->start;
 137        hcd->rsrc_len = resource_size(res);
 138        hcd->regs = devm_ioremap(&pdev->dev, res->start, hcd->rsrc_len);
 139        if (!hcd->regs) {
 140                dev_err(&pdev->dev, "Failed to remap I/O memory\n");
 141                err = -ENOMEM;
 142                goto fail_io;
 143        }
 144
 145        irq = platform_get_irq(pdev, 0);
 146        if (!irq) {
 147                dev_err(&pdev->dev, "Failed to get IRQ\n");
 148                err = -ENODEV;
 149                goto fail_io;
 150        }
 151
 152        if (exynos_ehci->otg)
 153                exynos_ehci->otg->set_host(exynos_ehci->otg, &hcd->self);
 154
 155        if (exynos_ehci->phy)
 156                usb_phy_init(exynos_ehci->phy);
 157
 158        ehci = hcd_to_ehci(hcd);
 159        ehci->caps = hcd->regs;
 160
 161        /* DMA burst Enable */
 162        writel(EHCI_INSNREG00_ENABLE_DMA_BURST, EHCI_INSNREG00(hcd->regs));
 163
 164        err = usb_add_hcd(hcd, irq, IRQF_SHARED);
 165        if (err) {
 166                dev_err(&pdev->dev, "Failed to add USB HCD\n");
 167                goto fail_add_hcd;
 168        }
 169        device_wakeup_enable(hcd->self.controller);
 170
 171        platform_set_drvdata(pdev, hcd);
 172
 173        return 0;
 174
 175fail_add_hcd:
 176        if (exynos_ehci->phy)
 177                usb_phy_shutdown(exynos_ehci->phy);
 178fail_io:
 179        clk_disable_unprepare(exynos_ehci->clk);
 180fail_clk:
 181        usb_put_hcd(hcd);
 182        return err;
 183}
 184
 185static int exynos_ehci_remove(struct platform_device *pdev)
 186{
 187        struct usb_hcd *hcd = platform_get_drvdata(pdev);
 188        struct exynos_ehci_hcd *exynos_ehci = to_exynos_ehci(hcd);
 189
 190        usb_remove_hcd(hcd);
 191
 192        if (exynos_ehci->otg)
 193                exynos_ehci->otg->set_host(exynos_ehci->otg, &hcd->self);
 194
 195        if (exynos_ehci->phy)
 196                usb_phy_shutdown(exynos_ehci->phy);
 197
 198        clk_disable_unprepare(exynos_ehci->clk);
 199
 200        usb_put_hcd(hcd);
 201
 202        return 0;
 203}
 204
 205#ifdef CONFIG_PM
 206static int exynos_ehci_suspend(struct device *dev)
 207{
 208        struct usb_hcd *hcd = dev_get_drvdata(dev);
 209        struct exynos_ehci_hcd *exynos_ehci = to_exynos_ehci(hcd);
 210
 211        bool do_wakeup = device_may_wakeup(dev);
 212        int rc;
 213
 214        rc = ehci_suspend(hcd, do_wakeup);
 215        if (rc)
 216                return rc;
 217
 218        if (exynos_ehci->otg)
 219                exynos_ehci->otg->set_host(exynos_ehci->otg, &hcd->self);
 220
 221        if (exynos_ehci->phy)
 222                usb_phy_shutdown(exynos_ehci->phy);
 223
 224        clk_disable_unprepare(exynos_ehci->clk);
 225
 226        return rc;
 227}
 228
 229static int exynos_ehci_resume(struct device *dev)
 230{
 231        struct usb_hcd *hcd = dev_get_drvdata(dev);
 232        struct exynos_ehci_hcd *exynos_ehci = to_exynos_ehci(hcd);
 233
 234        clk_prepare_enable(exynos_ehci->clk);
 235
 236        if (exynos_ehci->otg)
 237                exynos_ehci->otg->set_host(exynos_ehci->otg, &hcd->self);
 238
 239        if (exynos_ehci->phy)
 240                usb_phy_init(exynos_ehci->phy);
 241
 242        /* DMA burst Enable */
 243        writel(EHCI_INSNREG00_ENABLE_DMA_BURST, EHCI_INSNREG00(hcd->regs));
 244
 245        ehci_resume(hcd, false);
 246        return 0;
 247}
 248#else
 249#define exynos_ehci_suspend     NULL
 250#define exynos_ehci_resume      NULL
 251#endif
 252
 253static const struct dev_pm_ops exynos_ehci_pm_ops = {
 254        .suspend        = exynos_ehci_suspend,
 255        .resume         = exynos_ehci_resume,
 256};
 257
 258#ifdef CONFIG_OF
 259static const struct of_device_id exynos_ehci_match[] = {
 260        { .compatible = "samsung,exynos4210-ehci" },
 261        { .compatible = "samsung,exynos5440-ehci" },
 262        {},
 263};
 264MODULE_DEVICE_TABLE(of, exynos_ehci_match);
 265#endif
 266
 267static struct platform_driver exynos_ehci_driver = {
 268        .probe          = exynos_ehci_probe,
 269        .remove         = exynos_ehci_remove,
 270        .shutdown       = usb_hcd_platform_shutdown,
 271        .driver = {
 272                .name   = "exynos-ehci",
 273                .owner  = THIS_MODULE,
 274                .pm     = &exynos_ehci_pm_ops,
 275                .of_match_table = of_match_ptr(exynos_ehci_match),
 276        }
 277};
 278static const struct ehci_driver_overrides exynos_overrides __initdata = {
 279        .extra_priv_size = sizeof(struct exynos_ehci_hcd),
 280};
 281
 282static int __init ehci_exynos_init(void)
 283{
 284        if (usb_disabled())
 285                return -ENODEV;
 286
 287        pr_info("%s: " DRIVER_DESC "\n", hcd_name);
 288        ehci_init_driver(&exynos_ehci_hc_driver, &exynos_overrides);
 289        return platform_driver_register(&exynos_ehci_driver);
 290}
 291module_init(ehci_exynos_init);
 292
 293static void __exit ehci_exynos_cleanup(void)
 294{
 295        platform_driver_unregister(&exynos_ehci_driver);
 296}
 297module_exit(ehci_exynos_cleanup);
 298
 299MODULE_DESCRIPTION(DRIVER_DESC);
 300MODULE_ALIAS("platform:exynos-ehci");
 301MODULE_AUTHOR("Jingoo Han");
 302MODULE_AUTHOR("Joonyoung Shim");
 303MODULE_LICENSE("GPL v2");
 304