linux/drivers/usb/phy/phy-generic.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * NOP USB transceiver for all USB transceiver which are either built-in
   4 * into USB IP or which are mostly autonomous.
   5 *
   6 * Copyright (C) 2009 Texas Instruments Inc
   7 * Author: Ajay Kumar Gupta <ajay.gupta@ti.com>
   8 *
   9 * Current status:
  10 *      This provides a "nop" transceiver for PHYs which are
  11 *      autonomous such as isp1504, isp1707, etc.
  12 */
  13
  14#include <linux/module.h>
  15#include <linux/platform_device.h>
  16#include <linux/dma-mapping.h>
  17#include <linux/usb/gadget.h>
  18#include <linux/usb/otg.h>
  19#include <linux/usb/usb_phy_generic.h>
  20#include <linux/slab.h>
  21#include <linux/clk.h>
  22#include <linux/regulator/consumer.h>
  23#include <linux/of.h>
  24#include <linux/gpio/consumer.h>
  25#include <linux/delay.h>
  26
  27#include "phy-generic.h"
  28
  29#define VBUS_IRQ_FLAGS \
  30        (IRQF_SHARED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | \
  31                IRQF_ONESHOT)
  32
  33struct platform_device *usb_phy_generic_register(void)
  34{
  35        return platform_device_register_simple("usb_phy_generic",
  36                        PLATFORM_DEVID_AUTO, NULL, 0);
  37}
  38EXPORT_SYMBOL_GPL(usb_phy_generic_register);
  39
  40void usb_phy_generic_unregister(struct platform_device *pdev)
  41{
  42        platform_device_unregister(pdev);
  43}
  44EXPORT_SYMBOL_GPL(usb_phy_generic_unregister);
  45
  46static int nop_set_suspend(struct usb_phy *x, int suspend)
  47{
  48        struct usb_phy_generic *nop = dev_get_drvdata(x->dev);
  49
  50        if (!IS_ERR(nop->clk)) {
  51                if (suspend)
  52                        clk_disable_unprepare(nop->clk);
  53                else
  54                        clk_prepare_enable(nop->clk);
  55        }
  56
  57        return 0;
  58}
  59
  60static void nop_reset(struct usb_phy_generic *nop)
  61{
  62        if (!nop->gpiod_reset)
  63                return;
  64
  65        gpiod_set_value_cansleep(nop->gpiod_reset, 1);
  66        usleep_range(10000, 20000);
  67        gpiod_set_value_cansleep(nop->gpiod_reset, 0);
  68}
  69
  70/* interface to regulator framework */
  71static void nop_set_vbus_draw(struct usb_phy_generic *nop, unsigned mA)
  72{
  73        struct regulator *vbus_draw = nop->vbus_draw;
  74        int enabled;
  75        int ret;
  76
  77        if (!vbus_draw)
  78                return;
  79
  80        enabled = nop->vbus_draw_enabled;
  81        if (mA) {
  82                regulator_set_current_limit(vbus_draw, 0, 1000 * mA);
  83                if (!enabled) {
  84                        ret = regulator_enable(vbus_draw);
  85                        if (ret < 0)
  86                                return;
  87                        nop->vbus_draw_enabled = 1;
  88                }
  89        } else {
  90                if (enabled) {
  91                        ret = regulator_disable(vbus_draw);
  92                        if (ret < 0)
  93                                return;
  94                        nop->vbus_draw_enabled = 0;
  95                }
  96        }
  97        nop->mA = mA;
  98}
  99
 100
 101static irqreturn_t nop_gpio_vbus_thread(int irq, void *data)
 102{
 103        struct usb_phy_generic *nop = data;
 104        struct usb_otg *otg = nop->phy.otg;
 105        int vbus, status;
 106
 107        vbus = gpiod_get_value(nop->gpiod_vbus);
 108        if ((vbus ^ nop->vbus) == 0)
 109                return IRQ_HANDLED;
 110        nop->vbus = vbus;
 111
 112        if (vbus) {
 113                status = USB_EVENT_VBUS;
 114                otg->state = OTG_STATE_B_PERIPHERAL;
 115                nop->phy.last_event = status;
 116
 117                /* drawing a "unit load" is *always* OK, except for OTG */
 118                nop_set_vbus_draw(nop, 100);
 119
 120                atomic_notifier_call_chain(&nop->phy.notifier, status,
 121                                           otg->gadget);
 122        } else {
 123                nop_set_vbus_draw(nop, 0);
 124
 125                status = USB_EVENT_NONE;
 126                otg->state = OTG_STATE_B_IDLE;
 127                nop->phy.last_event = status;
 128
 129                atomic_notifier_call_chain(&nop->phy.notifier, status,
 130                                           otg->gadget);
 131        }
 132        return IRQ_HANDLED;
 133}
 134
 135int usb_gen_phy_init(struct usb_phy *phy)
 136{
 137        struct usb_phy_generic *nop = dev_get_drvdata(phy->dev);
 138        int ret;
 139
 140        if (!IS_ERR(nop->vcc)) {
 141                if (regulator_enable(nop->vcc))
 142                        dev_err(phy->dev, "Failed to enable power\n");
 143        }
 144
 145        if (!IS_ERR(nop->clk)) {
 146                ret = clk_prepare_enable(nop->clk);
 147                if (ret)
 148                        return ret;
 149        }
 150
 151        nop_reset(nop);
 152
 153        return 0;
 154}
 155EXPORT_SYMBOL_GPL(usb_gen_phy_init);
 156
 157void usb_gen_phy_shutdown(struct usb_phy *phy)
 158{
 159        struct usb_phy_generic *nop = dev_get_drvdata(phy->dev);
 160
 161        gpiod_set_value_cansleep(nop->gpiod_reset, 1);
 162
 163        if (!IS_ERR(nop->clk))
 164                clk_disable_unprepare(nop->clk);
 165
 166        if (!IS_ERR(nop->vcc)) {
 167                if (regulator_disable(nop->vcc))
 168                        dev_err(phy->dev, "Failed to disable power\n");
 169        }
 170}
 171EXPORT_SYMBOL_GPL(usb_gen_phy_shutdown);
 172
 173static int nop_set_peripheral(struct usb_otg *otg, struct usb_gadget *gadget)
 174{
 175        if (!otg)
 176                return -ENODEV;
 177
 178        if (!gadget) {
 179                otg->gadget = NULL;
 180                return -ENODEV;
 181        }
 182
 183        otg->gadget = gadget;
 184        if (otg->state == OTG_STATE_B_PERIPHERAL)
 185                atomic_notifier_call_chain(&otg->usb_phy->notifier,
 186                                           USB_EVENT_VBUS, otg->gadget);
 187        else
 188                otg->state = OTG_STATE_B_IDLE;
 189        return 0;
 190}
 191
 192static int nop_set_host(struct usb_otg *otg, struct usb_bus *host)
 193{
 194        if (!otg)
 195                return -ENODEV;
 196
 197        if (!host) {
 198                otg->host = NULL;
 199                return -ENODEV;
 200        }
 201
 202        otg->host = host;
 203        return 0;
 204}
 205
 206int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_generic *nop)
 207{
 208        enum usb_phy_type type = USB_PHY_TYPE_USB2;
 209        int err = 0;
 210
 211        u32 clk_rate = 0;
 212        bool needs_vcc = false, needs_clk = false;
 213
 214        if (dev->of_node) {
 215                struct device_node *node = dev->of_node;
 216
 217                if (of_property_read_u32(node, "clock-frequency", &clk_rate))
 218                        clk_rate = 0;
 219
 220                needs_vcc = of_property_read_bool(node, "vcc-supply");
 221                needs_clk = of_property_read_bool(node, "clocks");
 222        }
 223        nop->gpiod_reset = devm_gpiod_get_optional(dev, "reset",
 224                                                   GPIOD_ASIS);
 225        err = PTR_ERR_OR_ZERO(nop->gpiod_reset);
 226        if (!err) {
 227                nop->gpiod_vbus = devm_gpiod_get_optional(dev,
 228                                                 "vbus-detect",
 229                                                 GPIOD_ASIS);
 230                err = PTR_ERR_OR_ZERO(nop->gpiod_vbus);
 231        }
 232
 233        if (err == -EPROBE_DEFER)
 234                return -EPROBE_DEFER;
 235        if (err) {
 236                dev_err(dev, "Error requesting RESET or VBUS GPIO\n");
 237                return err;
 238        }
 239        if (nop->gpiod_reset)
 240                gpiod_direction_output(nop->gpiod_reset, 1);
 241
 242        nop->phy.otg = devm_kzalloc(dev, sizeof(*nop->phy.otg),
 243                        GFP_KERNEL);
 244        if (!nop->phy.otg)
 245                return -ENOMEM;
 246
 247        nop->clk = devm_clk_get(dev, "main_clk");
 248        if (IS_ERR(nop->clk)) {
 249                dev_dbg(dev, "Can't get phy clock: %ld\n",
 250                                        PTR_ERR(nop->clk));
 251                if (needs_clk)
 252                        return PTR_ERR(nop->clk);
 253        }
 254
 255        if (!IS_ERR(nop->clk) && clk_rate) {
 256                err = clk_set_rate(nop->clk, clk_rate);
 257                if (err) {
 258                        dev_err(dev, "Error setting clock rate\n");
 259                        return err;
 260                }
 261        }
 262
 263        nop->vcc = devm_regulator_get(dev, "vcc");
 264        if (IS_ERR(nop->vcc)) {
 265                dev_dbg(dev, "Error getting vcc regulator: %ld\n",
 266                                        PTR_ERR(nop->vcc));
 267                if (needs_vcc)
 268                        return -EPROBE_DEFER;
 269        }
 270
 271        nop->dev                = dev;
 272        nop->phy.dev            = nop->dev;
 273        nop->phy.label          = "nop-xceiv";
 274        nop->phy.set_suspend    = nop_set_suspend;
 275        nop->phy.type           = type;
 276
 277        nop->phy.otg->state             = OTG_STATE_UNDEFINED;
 278        nop->phy.otg->usb_phy           = &nop->phy;
 279        nop->phy.otg->set_host          = nop_set_host;
 280        nop->phy.otg->set_peripheral    = nop_set_peripheral;
 281
 282        return 0;
 283}
 284EXPORT_SYMBOL_GPL(usb_phy_gen_create_phy);
 285
 286static int usb_phy_generic_probe(struct platform_device *pdev)
 287{
 288        struct device *dev = &pdev->dev;
 289        struct usb_phy_generic  *nop;
 290        int err;
 291
 292        nop = devm_kzalloc(dev, sizeof(*nop), GFP_KERNEL);
 293        if (!nop)
 294                return -ENOMEM;
 295
 296        err = usb_phy_gen_create_phy(dev, nop);
 297        if (err)
 298                return err;
 299        if (nop->gpiod_vbus) {
 300                err = devm_request_threaded_irq(&pdev->dev,
 301                                                gpiod_to_irq(nop->gpiod_vbus),
 302                                                NULL, nop_gpio_vbus_thread,
 303                                                VBUS_IRQ_FLAGS, "vbus_detect",
 304                                                nop);
 305                if (err) {
 306                        dev_err(&pdev->dev, "can't request irq %i, err: %d\n",
 307                                gpiod_to_irq(nop->gpiod_vbus), err);
 308                        return err;
 309                }
 310                nop->phy.otg->state = gpiod_get_value(nop->gpiod_vbus) ?
 311                        OTG_STATE_B_PERIPHERAL : OTG_STATE_B_IDLE;
 312        }
 313
 314        nop->phy.init           = usb_gen_phy_init;
 315        nop->phy.shutdown       = usb_gen_phy_shutdown;
 316
 317        err = usb_add_phy_dev(&nop->phy);
 318        if (err) {
 319                dev_err(&pdev->dev, "can't register transceiver, err: %d\n",
 320                        err);
 321                return err;
 322        }
 323
 324        platform_set_drvdata(pdev, nop);
 325
 326        return 0;
 327}
 328
 329static int usb_phy_generic_remove(struct platform_device *pdev)
 330{
 331        struct usb_phy_generic *nop = platform_get_drvdata(pdev);
 332
 333        usb_remove_phy(&nop->phy);
 334
 335        return 0;
 336}
 337
 338static const struct of_device_id nop_xceiv_dt_ids[] = {
 339        { .compatible = "usb-nop-xceiv" },
 340        { }
 341};
 342
 343MODULE_DEVICE_TABLE(of, nop_xceiv_dt_ids);
 344
 345static struct platform_driver usb_phy_generic_driver = {
 346        .probe          = usb_phy_generic_probe,
 347        .remove         = usb_phy_generic_remove,
 348        .driver         = {
 349                .name   = "usb_phy_generic",
 350                .of_match_table = nop_xceiv_dt_ids,
 351        },
 352};
 353
 354static int __init usb_phy_generic_init(void)
 355{
 356        return platform_driver_register(&usb_phy_generic_driver);
 357}
 358subsys_initcall(usb_phy_generic_init);
 359
 360static void __exit usb_phy_generic_exit(void)
 361{
 362        platform_driver_unregister(&usb_phy_generic_driver);
 363}
 364module_exit(usb_phy_generic_exit);
 365
 366MODULE_ALIAS("platform:usb_phy_generic");
 367MODULE_AUTHOR("Texas Instruments Inc");
 368MODULE_DESCRIPTION("NOP USB Transceiver driver");
 369MODULE_LICENSE("GPL");
 370