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