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        int err, irq, clk = 0;
 136
 137        if (usb_disabled())
 138                return -ENODEV;
 139
 140        irq = platform_get_irq(dev, 0);
 141        if (irq < 0) {
 142                dev_err(&dev->dev, "no irq provided");
 143                return irq;
 144        }
 145
 146        res_mem = platform_get_resource(dev, IORESOURCE_MEM, 0);
 147        if (!res_mem) {
 148                dev_err(&dev->dev, "no memory resource provided");
 149                return -ENXIO;
 150        }
 151
 152        hcd = usb_create_hcd(&ohci_platform_hc_driver, &dev->dev,
 153                        dev_name(&dev->dev));
 154        if (!hcd)
 155                return -ENOMEM;
 156
 157        platform_set_drvdata(dev, hcd);
 158        dev->dev.platform_data = pdata;
 159        priv = hcd_to_ohci_priv(hcd);
 160
 161        priv->phy = devm_phy_get(&dev->dev, "usb");
 162        if (IS_ERR(priv->phy)) {
 163                err = PTR_ERR(priv->phy);
 164                goto err_put_hcd;
 165        }
 166
 167        for (clk = 0; clk < USB_MAX_CLKS; clk++) {
 168                priv->clks[clk] = of_clk_get(dev->dev.of_node, clk);
 169                if (IS_ERR(priv->clks[clk])) {
 170                        err = PTR_ERR(priv->clks[clk]);
 171                        if (err == -EPROBE_DEFER)
 172                                goto err_put_clks;
 173                        priv->clks[clk] = NULL;
 174                        break;
 175                }
 176        }
 177
 178        /* some SoCs don't have a dedicated 48Mhz clock, but those that
 179           do need the rate to be explicitly set */
 180        priv->clk48 = devm_clk_get(&dev->dev, "clk48");
 181        if (IS_ERR(priv->clk48)) {
 182                dev_info(&dev->dev, "48MHz clk not found\n");
 183                priv->clk48 = NULL;
 184        }
 185
 186        priv->pwr =
 187                devm_reset_control_get_optional_shared(&dev->dev, "power");
 188        if (IS_ERR(priv->pwr)) {
 189                err = PTR_ERR(priv->pwr);
 190                goto err_put_clks;
 191        }
 192
 193        priv->rst =
 194                devm_reset_control_get_optional_shared(&dev->dev, "softreset");
 195        if (IS_ERR(priv->rst)) {
 196                err = PTR_ERR(priv->rst);
 197                goto err_put_clks;
 198        }
 199
 200        if (pdata->power_on) {
 201                err = pdata->power_on(dev);
 202                if (err < 0)
 203                        goto err_power;
 204        }
 205
 206        hcd->rsrc_start = res_mem->start;
 207        hcd->rsrc_len = resource_size(res_mem);
 208
 209        hcd->regs = devm_ioremap_resource(&dev->dev, res_mem);
 210        if (IS_ERR(hcd->regs)) {
 211                err = PTR_ERR(hcd->regs);
 212                goto err_power;
 213        }
 214        err = usb_add_hcd(hcd, irq, IRQF_SHARED);
 215        if (err)
 216                goto err_power;
 217
 218        device_wakeup_enable(hcd->self.controller);
 219
 220        platform_set_drvdata(dev, hcd);
 221
 222        return err;
 223
 224err_power:
 225        if (pdata->power_off)
 226                pdata->power_off(dev);
 227
 228err_put_clks:
 229        while (--clk >= 0)
 230                clk_put(priv->clks[clk]);
 231err_put_hcd:
 232        if (pdata == &ohci_platform_defaults)
 233                dev->dev.platform_data = NULL;
 234
 235        usb_put_hcd(hcd);
 236
 237        return err;
 238}
 239
 240static int st_ohci_platform_remove(struct platform_device *dev)
 241{
 242        struct usb_hcd *hcd = platform_get_drvdata(dev);
 243        struct usb_ohci_pdata *pdata = dev_get_platdata(&dev->dev);
 244        struct st_ohci_platform_priv *priv = hcd_to_ohci_priv(hcd);
 245        int clk;
 246
 247        usb_remove_hcd(hcd);
 248
 249        if (pdata->power_off)
 250                pdata->power_off(dev);
 251
 252
 253        for (clk = 0; clk < USB_MAX_CLKS && priv->clks[clk]; clk++)
 254                clk_put(priv->clks[clk]);
 255
 256        usb_put_hcd(hcd);
 257
 258        if (pdata == &ohci_platform_defaults)
 259                dev->dev.platform_data = NULL;
 260
 261        return 0;
 262}
 263
 264#ifdef CONFIG_PM_SLEEP
 265
 266static int st_ohci_suspend(struct device *dev)
 267{
 268        struct usb_hcd *hcd = dev_get_drvdata(dev);
 269        struct usb_ohci_pdata *pdata = dev->platform_data;
 270        struct platform_device *pdev = to_platform_device(dev);
 271        bool do_wakeup = device_may_wakeup(dev);
 272        int ret;
 273
 274        ret = ohci_suspend(hcd, do_wakeup);
 275        if (ret)
 276                return ret;
 277
 278        if (pdata->power_suspend)
 279                pdata->power_suspend(pdev);
 280
 281        return ret;
 282}
 283
 284static int st_ohci_resume(struct device *dev)
 285{
 286        struct usb_hcd *hcd = dev_get_drvdata(dev);
 287        struct usb_ohci_pdata *pdata = dev_get_platdata(dev);
 288        struct platform_device *pdev = to_platform_device(dev);
 289        int err;
 290
 291        if (pdata->power_on) {
 292                err = pdata->power_on(pdev);
 293                if (err < 0)
 294                        return err;
 295        }
 296
 297        ohci_resume(hcd, false);
 298        return 0;
 299}
 300
 301static SIMPLE_DEV_PM_OPS(st_ohci_pm_ops, st_ohci_suspend, st_ohci_resume);
 302
 303#endif /* CONFIG_PM_SLEEP */
 304
 305static const struct of_device_id st_ohci_platform_ids[] = {
 306        { .compatible = "st,st-ohci-300x", },
 307        { /* sentinel */ }
 308};
 309MODULE_DEVICE_TABLE(of, st_ohci_platform_ids);
 310
 311static struct platform_driver ohci_platform_driver = {
 312        .probe          = st_ohci_platform_probe,
 313        .remove         = st_ohci_platform_remove,
 314        .shutdown       = usb_hcd_platform_shutdown,
 315        .driver         = {
 316                .name   = "st-ohci",
 317#ifdef CONFIG_PM_SLEEP
 318                .pm     = &st_ohci_pm_ops,
 319#endif
 320                .of_match_table = st_ohci_platform_ids,
 321        }
 322};
 323
 324static int __init ohci_platform_init(void)
 325{
 326        if (usb_disabled())
 327                return -ENODEV;
 328
 329        pr_info("%s: " DRIVER_DESC "\n", hcd_name);
 330
 331        ohci_init_driver(&ohci_platform_hc_driver, &platform_overrides);
 332        return platform_driver_register(&ohci_platform_driver);
 333}
 334module_init(ohci_platform_init);
 335
 336static void __exit ohci_platform_cleanup(void)
 337{
 338        platform_driver_unregister(&ohci_platform_driver);
 339}
 340module_exit(ohci_platform_cleanup);
 341
 342MODULE_DESCRIPTION(DRIVER_DESC);
 343MODULE_AUTHOR("Peter Griffin <peter.griffin@linaro.org>");
 344MODULE_LICENSE("GPL");
 345