linux/drivers/usb/host/ohci-st.c
<<
>>
Prefs
   1/*
   2 * ST OHCI driver
   3 *
   4 * Copyright (C) 2014 STMicroelectronics – All Rights Reserved
   5 *
   6 * Author: Peter Griffin <peter.griffin@linaro.org>
   7 *
   8 * Derived from ohci-platform.c
   9 *
  10 * This program is free software; you can redistribute it and/or modify
  11 * it under the terms of the GNU General Public License version 2 as
  12 * published by the Free Software Foundation.
  13 */
  14
  15#include <linux/clk.h>
  16#include <linux/dma-mapping.h>
  17#include <linux/hrtimer.h>
  18#include <linux/io.h>
  19#include <linux/kernel.h>
  20#include <linux/module.h>
  21#include <linux/err.h>
  22#include <linux/phy/phy.h>
  23#include <linux/platform_device.h>
  24#include <linux/reset.h>
  25#include <linux/usb/ohci_pdriver.h>
  26#include <linux/usb.h>
  27#include <linux/usb/hcd.h>
  28
  29#include "ohci.h"
  30
  31#define USB_MAX_CLKS 3
  32
  33struct st_ohci_platform_priv {
  34        struct clk *clks[USB_MAX_CLKS];
  35        struct clk *clk48;
  36        struct reset_control *rst;
  37        struct reset_control *pwr;
  38        struct phy *phy;
  39};
  40
  41#define DRIVER_DESC "OHCI STMicroelectronics driver"
  42
  43#define hcd_to_ohci_priv(h) \
  44        ((struct st_ohci_platform_priv *)hcd_to_ohci(h)->priv)
  45
  46static const char hcd_name[] = "ohci-st";
  47
  48static int st_ohci_platform_power_on(struct platform_device *dev)
  49{
  50        struct usb_hcd *hcd = platform_get_drvdata(dev);
  51        struct st_ohci_platform_priv *priv = hcd_to_ohci_priv(hcd);
  52        int clk, ret;
  53
  54        ret = reset_control_deassert(priv->pwr);
  55        if (ret)
  56                return ret;
  57
  58        ret = reset_control_deassert(priv->rst);
  59        if (ret)
  60                goto err_assert_power;
  61
  62        /* some SoCs don't have a dedicated 48Mhz clock, but those that do
  63           need the rate to be explicitly set */
  64        if (priv->clk48) {
  65                ret = clk_set_rate(priv->clk48, 48000000);
  66                if (ret)
  67                        goto err_assert_reset;
  68        }
  69
  70        for (clk = 0; clk < USB_MAX_CLKS && priv->clks[clk]; clk++) {
  71                ret = clk_prepare_enable(priv->clks[clk]);
  72                if (ret)
  73                        goto err_disable_clks;
  74        }
  75
  76        ret = phy_init(priv->phy);
  77        if (ret)
  78                goto err_disable_clks;
  79
  80        ret = phy_power_on(priv->phy);
  81        if (ret)
  82                goto err_exit_phy;
  83
  84        return 0;
  85
  86err_exit_phy:
  87        phy_exit(priv->phy);
  88err_disable_clks:
  89        while (--clk >= 0)
  90                clk_disable_unprepare(priv->clks[clk]);
  91err_assert_reset:
  92        reset_control_assert(priv->rst);
  93err_assert_power:
  94        reset_control_assert(priv->pwr);
  95
  96        return ret;
  97}
  98
  99static void st_ohci_platform_power_off(struct platform_device *dev)
 100{
 101        struct usb_hcd *hcd = platform_get_drvdata(dev);
 102        struct st_ohci_platform_priv *priv = hcd_to_ohci_priv(hcd);
 103
 104        int clk;
 105
 106        reset_control_assert(priv->pwr);
 107
 108        reset_control_assert(priv->rst);
 109
 110        phy_power_off(priv->phy);
 111
 112        phy_exit(priv->phy);
 113
 114        for (clk = USB_MAX_CLKS - 1; clk >= 0; clk--)
 115                if (priv->clks[clk])
 116                        clk_disable_unprepare(priv->clks[clk]);
 117}
 118
 119static struct hc_driver __read_mostly ohci_platform_hc_driver;
 120
 121static const struct ohci_driver_overrides platform_overrides __initconst = {
 122        .product_desc =         "ST OHCI controller",
 123        .extra_priv_size =      sizeof(struct st_ohci_platform_priv),
 124};
 125
 126static struct usb_ohci_pdata ohci_platform_defaults = {
 127        .power_on =             st_ohci_platform_power_on,
 128        .power_suspend =        st_ohci_platform_power_off,
 129        .power_off =            st_ohci_platform_power_off,
 130};
 131
 132static int st_ohci_platform_probe(struct platform_device *dev)
 133{
 134        struct usb_hcd *hcd;
 135        struct resource *res_mem;
 136        struct usb_ohci_pdata *pdata = &ohci_platform_defaults;
 137        struct st_ohci_platform_priv *priv;
 138        struct ohci_hcd *ohci;
 139        int err, irq, clk = 0;
 140
 141        if (usb_disabled())
 142                return -ENODEV;
 143
 144        irq = platform_get_irq(dev, 0);
 145        if (irq < 0) {
 146                dev_err(&dev->dev, "no irq provided");
 147                return irq;
 148        }
 149
 150        res_mem = platform_get_resource(dev, IORESOURCE_MEM, 0);
 151        if (!res_mem) {
 152                dev_err(&dev->dev, "no memory resource provided");
 153                return -ENXIO;
 154        }
 155
 156        hcd = usb_create_hcd(&ohci_platform_hc_driver, &dev->dev,
 157                        dev_name(&dev->dev));
 158        if (!hcd)
 159                return -ENOMEM;
 160
 161        platform_set_drvdata(dev, hcd);
 162        dev->dev.platform_data = pdata;
 163        priv = hcd_to_ohci_priv(hcd);
 164        ohci = hcd_to_ohci(hcd);
 165
 166        priv->phy = devm_phy_get(&dev->dev, "usb");
 167        if (IS_ERR(priv->phy)) {
 168                err = PTR_ERR(priv->phy);
 169                goto err_put_hcd;
 170        }
 171
 172        for (clk = 0; clk < USB_MAX_CLKS; clk++) {
 173                priv->clks[clk] = of_clk_get(dev->dev.of_node, clk);
 174                if (IS_ERR(priv->clks[clk])) {
 175                        err = PTR_ERR(priv->clks[clk]);
 176                        if (err == -EPROBE_DEFER)
 177                                goto err_put_clks;
 178                        priv->clks[clk] = NULL;
 179                        break;
 180                }
 181        }
 182
 183        /* some SoCs don't have a dedicated 48Mhz clock, but those that
 184           do need the rate to be explicitly set */
 185        priv->clk48 = devm_clk_get(&dev->dev, "clk48");
 186        if (IS_ERR(priv->clk48)) {
 187                dev_info(&dev->dev, "48MHz clk not found\n");
 188                priv->clk48 = NULL;
 189        }
 190
 191        priv->pwr =
 192                devm_reset_control_get_optional_shared(&dev->dev, "power");
 193        if (IS_ERR(priv->pwr)) {
 194                err = PTR_ERR(priv->pwr);
 195                goto err_put_clks;
 196        }
 197
 198        priv->rst =
 199                devm_reset_control_get_optional_shared(&dev->dev, "softreset");
 200        if (IS_ERR(priv->rst)) {
 201                err = PTR_ERR(priv->rst);
 202                goto err_put_clks;
 203        }
 204
 205        if (pdata->power_on) {
 206                err = pdata->power_on(dev);
 207                if (err < 0)
 208                        goto err_power;
 209        }
 210
 211        hcd->rsrc_start = res_mem->start;
 212        hcd->rsrc_len = resource_size(res_mem);
 213
 214        hcd->regs = devm_ioremap_resource(&dev->dev, res_mem);
 215        if (IS_ERR(hcd->regs)) {
 216                err = PTR_ERR(hcd->regs);
 217                goto err_power;
 218        }
 219        err = usb_add_hcd(hcd, irq, IRQF_SHARED);
 220        if (err)
 221                goto err_power;
 222
 223        device_wakeup_enable(hcd->self.controller);
 224
 225        platform_set_drvdata(dev, hcd);
 226
 227        return err;
 228
 229err_power:
 230        if (pdata->power_off)
 231                pdata->power_off(dev);
 232
 233err_put_clks:
 234        while (--clk >= 0)
 235                clk_put(priv->clks[clk]);
 236err_put_hcd:
 237        if (pdata == &ohci_platform_defaults)
 238                dev->dev.platform_data = NULL;
 239
 240        usb_put_hcd(hcd);
 241
 242        return err;
 243}
 244
 245static int st_ohci_platform_remove(struct platform_device *dev)
 246{
 247        struct usb_hcd *hcd = platform_get_drvdata(dev);
 248        struct usb_ohci_pdata *pdata = dev_get_platdata(&dev->dev);
 249        struct st_ohci_platform_priv *priv = hcd_to_ohci_priv(hcd);
 250        int clk;
 251
 252        usb_remove_hcd(hcd);
 253
 254        if (pdata->power_off)
 255                pdata->power_off(dev);
 256
 257
 258        for (clk = 0; clk < USB_MAX_CLKS && priv->clks[clk]; clk++)
 259                clk_put(priv->clks[clk]);
 260
 261        usb_put_hcd(hcd);
 262
 263        if (pdata == &ohci_platform_defaults)
 264                dev->dev.platform_data = NULL;
 265
 266        return 0;
 267}
 268
 269#ifdef CONFIG_PM_SLEEP
 270
 271static int st_ohci_suspend(struct device *dev)
 272{
 273        struct usb_hcd *hcd = dev_get_drvdata(dev);
 274        struct usb_ohci_pdata *pdata = dev->platform_data;
 275        struct platform_device *pdev = to_platform_device(dev);
 276        bool do_wakeup = device_may_wakeup(dev);
 277        int ret;
 278
 279        ret = ohci_suspend(hcd, do_wakeup);
 280        if (ret)
 281                return ret;
 282
 283        if (pdata->power_suspend)
 284                pdata->power_suspend(pdev);
 285
 286        return ret;
 287}
 288
 289static int st_ohci_resume(struct device *dev)
 290{
 291        struct usb_hcd *hcd = dev_get_drvdata(dev);
 292        struct usb_ohci_pdata *pdata = dev_get_platdata(dev);
 293        struct platform_device *pdev = to_platform_device(dev);
 294        int err;
 295
 296        if (pdata->power_on) {
 297                err = pdata->power_on(pdev);
 298                if (err < 0)
 299                        return err;
 300        }
 301
 302        ohci_resume(hcd, false);
 303        return 0;
 304}
 305
 306static SIMPLE_DEV_PM_OPS(st_ohci_pm_ops, st_ohci_suspend, st_ohci_resume);
 307
 308#endif /* CONFIG_PM_SLEEP */
 309
 310static const struct of_device_id st_ohci_platform_ids[] = {
 311        { .compatible = "st,st-ohci-300x", },
 312        { /* sentinel */ }
 313};
 314MODULE_DEVICE_TABLE(of, st_ohci_platform_ids);
 315
 316static struct platform_driver ohci_platform_driver = {
 317        .probe          = st_ohci_platform_probe,
 318        .remove         = st_ohci_platform_remove,
 319        .shutdown       = usb_hcd_platform_shutdown,
 320        .driver         = {
 321                .name   = "st-ohci",
 322#ifdef CONFIG_PM_SLEEP
 323                .pm     = &st_ohci_pm_ops,
 324#endif
 325                .of_match_table = st_ohci_platform_ids,
 326        }
 327};
 328
 329static int __init ohci_platform_init(void)
 330{
 331        if (usb_disabled())
 332                return -ENODEV;
 333
 334        pr_info("%s: " DRIVER_DESC "\n", hcd_name);
 335
 336        ohci_init_driver(&ohci_platform_hc_driver, &platform_overrides);
 337        return platform_driver_register(&ohci_platform_driver);
 338}
 339module_init(ohci_platform_init);
 340
 341static void __exit ohci_platform_cleanup(void)
 342{
 343        platform_driver_unregister(&ohci_platform_driver);
 344}
 345module_exit(ohci_platform_cleanup);
 346
 347MODULE_DESCRIPTION(DRIVER_DESC);
 348MODULE_AUTHOR("Peter Griffin <peter.griffin@linaro.org>");
 349MODULE_LICENSE("GPL");
 350