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/phy/phy.h>
  23#include <linux/platform_device.h>
  24#include <linux/usb.h>
  25#include <linux/usb/hcd.h>
  26
  27#include "ehci.h"
  28
  29#define DRIVER_DESC "EHCI EXYNOS driver"
  30
  31#define EHCI_INSNREG00(base)                    (base + 0x90)
  32#define EHCI_INSNREG00_ENA_INCR16               (0x1 << 25)
  33#define EHCI_INSNREG00_ENA_INCR8                (0x1 << 24)
  34#define EHCI_INSNREG00_ENA_INCR4                (0x1 << 23)
  35#define EHCI_INSNREG00_ENA_INCRX_ALIGN          (0x1 << 22)
  36#define EHCI_INSNREG00_ENABLE_DMA_BURST \
  37        (EHCI_INSNREG00_ENA_INCR16 | EHCI_INSNREG00_ENA_INCR8 | \
  38         EHCI_INSNREG00_ENA_INCR4 | EHCI_INSNREG00_ENA_INCRX_ALIGN)
  39
  40static const char hcd_name[] = "ehci-exynos";
  41static struct hc_driver __read_mostly exynos_ehci_hc_driver;
  42
  43#define PHY_NUMBER 3
  44
  45struct exynos_ehci_hcd {
  46        struct clk *clk;
  47        struct phy *phy[PHY_NUMBER];
  48};
  49
  50#define to_exynos_ehci(hcd) (struct exynos_ehci_hcd *)(hcd_to_ehci(hcd)->priv)
  51
  52static int exynos_ehci_get_phy(struct device *dev,
  53                                struct exynos_ehci_hcd *exynos_ehci)
  54{
  55        struct device_node *child;
  56        struct phy *phy;
  57        int phy_number;
  58        int ret;
  59
  60        /* Get PHYs for the controller */
  61        for_each_available_child_of_node(dev->of_node, child) {
  62                ret = of_property_read_u32(child, "reg", &phy_number);
  63                if (ret) {
  64                        dev_err(dev, "Failed to parse device tree\n");
  65                        of_node_put(child);
  66                        return ret;
  67                }
  68
  69                if (phy_number >= PHY_NUMBER) {
  70                        dev_err(dev, "Invalid number of PHYs\n");
  71                        of_node_put(child);
  72                        return -EINVAL;
  73                }
  74
  75                phy = devm_of_phy_get(dev, child, NULL);
  76                exynos_ehci->phy[phy_number] = phy;
  77                if (IS_ERR(phy)) {
  78                        ret = PTR_ERR(phy);
  79                        if (ret == -EPROBE_DEFER) {
  80                                of_node_put(child);
  81                                return ret;
  82                        } else if (ret != -ENOSYS && ret != -ENODEV) {
  83                                dev_err(dev,
  84                                        "Error retrieving usb2 phy: %d\n", ret);
  85                                of_node_put(child);
  86                                return ret;
  87                        }
  88                }
  89        }
  90
  91        return 0;
  92}
  93
  94static int exynos_ehci_phy_enable(struct device *dev)
  95{
  96        struct usb_hcd *hcd = dev_get_drvdata(dev);
  97        struct exynos_ehci_hcd *exynos_ehci = to_exynos_ehci(hcd);
  98        int i;
  99        int ret = 0;
 100
 101        for (i = 0; ret == 0 && i < PHY_NUMBER; i++)
 102                if (!IS_ERR(exynos_ehci->phy[i]))
 103                        ret = phy_power_on(exynos_ehci->phy[i]);
 104        if (ret)
 105                for (i--; i >= 0; i--)
 106                        if (!IS_ERR(exynos_ehci->phy[i]))
 107                                phy_power_off(exynos_ehci->phy[i]);
 108
 109        return ret;
 110}
 111
 112static void exynos_ehci_phy_disable(struct device *dev)
 113{
 114        struct usb_hcd *hcd = dev_get_drvdata(dev);
 115        struct exynos_ehci_hcd *exynos_ehci = to_exynos_ehci(hcd);
 116        int i;
 117
 118        for (i = 0; i < PHY_NUMBER; i++)
 119                if (!IS_ERR(exynos_ehci->phy[i]))
 120                        phy_power_off(exynos_ehci->phy[i]);
 121}
 122
 123static void exynos_setup_vbus_gpio(struct device *dev)
 124{
 125        int err;
 126        int gpio;
 127
 128        if (!dev->of_node)
 129                return;
 130
 131        gpio = of_get_named_gpio(dev->of_node, "samsung,vbus-gpio", 0);
 132        if (!gpio_is_valid(gpio))
 133                return;
 134
 135        err = devm_gpio_request_one(dev, gpio, GPIOF_OUT_INIT_HIGH,
 136                                    "ehci_vbus_gpio");
 137        if (err)
 138                dev_err(dev, "can't request ehci vbus gpio %d", gpio);
 139}
 140
 141static int exynos_ehci_probe(struct platform_device *pdev)
 142{
 143        struct exynos_ehci_hcd *exynos_ehci;
 144        struct usb_hcd *hcd;
 145        struct ehci_hcd *ehci;
 146        struct resource *res;
 147        int irq;
 148        int err;
 149
 150        /*
 151         * Right now device-tree probed devices don't get dma_mask set.
 152         * Since shared usb code relies on it, set it here for now.
 153         * Once we move to full device tree support this will vanish off.
 154         */
 155        err = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
 156        if (err)
 157                return err;
 158
 159        exynos_setup_vbus_gpio(&pdev->dev);
 160
 161        hcd = usb_create_hcd(&exynos_ehci_hc_driver,
 162                             &pdev->dev, dev_name(&pdev->dev));
 163        if (!hcd) {
 164                dev_err(&pdev->dev, "Unable to create HCD\n");
 165                return -ENOMEM;
 166        }
 167        exynos_ehci = to_exynos_ehci(hcd);
 168
 169        if (of_device_is_compatible(pdev->dev.of_node,
 170                                        "samsung,exynos5440-ehci"))
 171                goto skip_phy;
 172
 173        err = exynos_ehci_get_phy(&pdev->dev, exynos_ehci);
 174        if (err)
 175                goto fail_clk;
 176
 177skip_phy:
 178
 179        exynos_ehci->clk = devm_clk_get(&pdev->dev, "usbhost");
 180
 181        if (IS_ERR(exynos_ehci->clk)) {
 182                dev_err(&pdev->dev, "Failed to get usbhost clock\n");
 183                err = PTR_ERR(exynos_ehci->clk);
 184                goto fail_clk;
 185        }
 186
 187        err = clk_prepare_enable(exynos_ehci->clk);
 188        if (err)
 189                goto fail_clk;
 190
 191        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 192        hcd->regs = devm_ioremap_resource(&pdev->dev, res);
 193        if (IS_ERR(hcd->regs)) {
 194                err = PTR_ERR(hcd->regs);
 195                goto fail_io;
 196        }
 197
 198        hcd->rsrc_start = res->start;
 199        hcd->rsrc_len = resource_size(res);
 200
 201        irq = platform_get_irq(pdev, 0);
 202        if (!irq) {
 203                dev_err(&pdev->dev, "Failed to get IRQ\n");
 204                err = -ENODEV;
 205                goto fail_io;
 206        }
 207
 208        err = exynos_ehci_phy_enable(&pdev->dev);
 209        if (err) {
 210                dev_err(&pdev->dev, "Failed to enable USB phy\n");
 211                goto fail_io;
 212        }
 213
 214        ehci = hcd_to_ehci(hcd);
 215        ehci->caps = hcd->regs;
 216
 217        /* DMA burst Enable */
 218        writel(EHCI_INSNREG00_ENABLE_DMA_BURST, EHCI_INSNREG00(hcd->regs));
 219
 220        err = usb_add_hcd(hcd, irq, IRQF_SHARED);
 221        if (err) {
 222                dev_err(&pdev->dev, "Failed to add USB HCD\n");
 223                goto fail_add_hcd;
 224        }
 225        device_wakeup_enable(hcd->self.controller);
 226
 227        platform_set_drvdata(pdev, hcd);
 228
 229        return 0;
 230
 231fail_add_hcd:
 232        exynos_ehci_phy_disable(&pdev->dev);
 233fail_io:
 234        clk_disable_unprepare(exynos_ehci->clk);
 235fail_clk:
 236        usb_put_hcd(hcd);
 237        return err;
 238}
 239
 240static int exynos_ehci_remove(struct platform_device *pdev)
 241{
 242        struct usb_hcd *hcd = platform_get_drvdata(pdev);
 243        struct exynos_ehci_hcd *exynos_ehci = to_exynos_ehci(hcd);
 244
 245        usb_remove_hcd(hcd);
 246
 247        exynos_ehci_phy_disable(&pdev->dev);
 248
 249        clk_disable_unprepare(exynos_ehci->clk);
 250
 251        usb_put_hcd(hcd);
 252
 253        return 0;
 254}
 255
 256#ifdef CONFIG_PM
 257static int exynos_ehci_suspend(struct device *dev)
 258{
 259        struct usb_hcd *hcd = dev_get_drvdata(dev);
 260        struct exynos_ehci_hcd *exynos_ehci = to_exynos_ehci(hcd);
 261
 262        bool do_wakeup = device_may_wakeup(dev);
 263        int rc;
 264
 265        rc = ehci_suspend(hcd, do_wakeup);
 266        if (rc)
 267                return rc;
 268
 269        exynos_ehci_phy_disable(dev);
 270
 271        clk_disable_unprepare(exynos_ehci->clk);
 272
 273        return rc;
 274}
 275
 276static int exynos_ehci_resume(struct device *dev)
 277{
 278        struct usb_hcd *hcd = dev_get_drvdata(dev);
 279        struct exynos_ehci_hcd *exynos_ehci = to_exynos_ehci(hcd);
 280        int ret;
 281
 282        ret = clk_prepare_enable(exynos_ehci->clk);
 283        if (ret)
 284                return ret;
 285
 286        ret = exynos_ehci_phy_enable(dev);
 287        if (ret) {
 288                dev_err(dev, "Failed to enable USB phy\n");
 289                clk_disable_unprepare(exynos_ehci->clk);
 290                return ret;
 291        }
 292
 293        /* DMA burst Enable */
 294        writel(EHCI_INSNREG00_ENABLE_DMA_BURST, EHCI_INSNREG00(hcd->regs));
 295
 296        ehci_resume(hcd, false);
 297        return 0;
 298}
 299#else
 300#define exynos_ehci_suspend     NULL
 301#define exynos_ehci_resume      NULL
 302#endif
 303
 304static const struct dev_pm_ops exynos_ehci_pm_ops = {
 305        .suspend        = exynos_ehci_suspend,
 306        .resume         = exynos_ehci_resume,
 307};
 308
 309#ifdef CONFIG_OF
 310static const struct of_device_id exynos_ehci_match[] = {
 311        { .compatible = "samsung,exynos4210-ehci" },
 312        { .compatible = "samsung,exynos5440-ehci" },
 313        {},
 314};
 315MODULE_DEVICE_TABLE(of, exynos_ehci_match);
 316#endif
 317
 318static struct platform_driver exynos_ehci_driver = {
 319        .probe          = exynos_ehci_probe,
 320        .remove         = exynos_ehci_remove,
 321        .shutdown       = usb_hcd_platform_shutdown,
 322        .driver = {
 323                .name   = "exynos-ehci",
 324                .pm     = &exynos_ehci_pm_ops,
 325                .of_match_table = of_match_ptr(exynos_ehci_match),
 326        }
 327};
 328static const struct ehci_driver_overrides exynos_overrides __initconst = {
 329        .extra_priv_size = sizeof(struct exynos_ehci_hcd),
 330};
 331
 332static int __init ehci_exynos_init(void)
 333{
 334        if (usb_disabled())
 335                return -ENODEV;
 336
 337        pr_info("%s: " DRIVER_DESC "\n", hcd_name);
 338        ehci_init_driver(&exynos_ehci_hc_driver, &exynos_overrides);
 339        return platform_driver_register(&exynos_ehci_driver);
 340}
 341module_init(ehci_exynos_init);
 342
 343static void __exit ehci_exynos_cleanup(void)
 344{
 345        platform_driver_unregister(&exynos_ehci_driver);
 346}
 347module_exit(ehci_exynos_cleanup);
 348
 349MODULE_DESCRIPTION(DRIVER_DESC);
 350MODULE_ALIAS("platform:exynos-ehci");
 351MODULE_AUTHOR("Jingoo Han");
 352MODULE_AUTHOR("Joonyoung Shim");
 353MODULE_LICENSE("GPL v2");
 354