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