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