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