linux/drivers/phy/renesas/phy-rcar-gen3-usb2.c
<<
>>
Prefs
   1/*
   2 * Renesas R-Car Gen3 for USB2.0 PHY driver
   3 *
   4 * Copyright (C) 2015 Renesas Electronics Corporation
   5 *
   6 * This is based on the phy-rcar-gen2 driver:
   7 * Copyright (C) 2014 Renesas Solutions Corp.
   8 * Copyright (C) 2014 Cogent Embedded, Inc.
   9 *
  10 * This program is free software; you can redistribute it and/or modify
  11 * it under the terms of the GNU General Public License version 2 as
  12 * published by the Free Software Foundation.
  13 */
  14
  15#include <linux/extcon.h>
  16#include <linux/interrupt.h>
  17#include <linux/io.h>
  18#include <linux/module.h>
  19#include <linux/of.h>
  20#include <linux/of_address.h>
  21#include <linux/phy/phy.h>
  22#include <linux/platform_device.h>
  23#include <linux/pm_runtime.h>
  24#include <linux/regulator/consumer.h>
  25#include <linux/workqueue.h>
  26
  27/******* USB2.0 Host registers (original offset is +0x200) *******/
  28#define USB2_INT_ENABLE         0x000
  29#define USB2_USBCTR             0x00c
  30#define USB2_SPD_RSM_TIMSET     0x10c
  31#define USB2_OC_TIMSET          0x110
  32#define USB2_COMMCTRL           0x600
  33#define USB2_OBINTSTA           0x604
  34#define USB2_OBINTEN            0x608
  35#define USB2_VBCTRL             0x60c
  36#define USB2_LINECTRL1          0x610
  37#define USB2_ADPCTRL            0x630
  38
  39/* INT_ENABLE */
  40#define USB2_INT_ENABLE_UCOM_INTEN      BIT(3)
  41#define USB2_INT_ENABLE_USBH_INTB_EN    BIT(2)
  42#define USB2_INT_ENABLE_USBH_INTA_EN    BIT(1)
  43#define USB2_INT_ENABLE_INIT            (USB2_INT_ENABLE_UCOM_INTEN | \
  44                                         USB2_INT_ENABLE_USBH_INTB_EN | \
  45                                         USB2_INT_ENABLE_USBH_INTA_EN)
  46
  47/* USBCTR */
  48#define USB2_USBCTR_DIRPD       BIT(2)
  49#define USB2_USBCTR_PLL_RST     BIT(1)
  50
  51/* SPD_RSM_TIMSET */
  52#define USB2_SPD_RSM_TIMSET_INIT        0x014e029b
  53
  54/* OC_TIMSET */
  55#define USB2_OC_TIMSET_INIT             0x000209ab
  56
  57/* COMMCTRL */
  58#define USB2_COMMCTRL_OTG_PERI          BIT(31) /* 1 = Peripheral mode */
  59
  60/* OBINTSTA and OBINTEN */
  61#define USB2_OBINT_SESSVLDCHG           BIT(12)
  62#define USB2_OBINT_IDDIGCHG             BIT(11)
  63#define USB2_OBINT_BITS                 (USB2_OBINT_SESSVLDCHG | \
  64                                         USB2_OBINT_IDDIGCHG)
  65
  66/* VBCTRL */
  67#define USB2_VBCTRL_DRVVBUSSEL          BIT(8)
  68
  69/* LINECTRL1 */
  70#define USB2_LINECTRL1_DPRPD_EN         BIT(19)
  71#define USB2_LINECTRL1_DP_RPD           BIT(18)
  72#define USB2_LINECTRL1_DMRPD_EN         BIT(17)
  73#define USB2_LINECTRL1_DM_RPD           BIT(16)
  74#define USB2_LINECTRL1_OPMODE_NODRV     BIT(6)
  75
  76/* ADPCTRL */
  77#define USB2_ADPCTRL_OTGSESSVLD         BIT(20)
  78#define USB2_ADPCTRL_IDDIG              BIT(19)
  79#define USB2_ADPCTRL_IDPULLUP           BIT(5)  /* 1 = ID sampling is enabled */
  80#define USB2_ADPCTRL_DRVVBUS            BIT(4)
  81
  82struct rcar_gen3_chan {
  83        void __iomem *base;
  84        struct extcon_dev *extcon;
  85        struct phy *phy;
  86        struct regulator *vbus;
  87        struct work_struct work;
  88        bool extcon_host;
  89        bool has_otg;
  90};
  91
  92static void rcar_gen3_phy_usb2_work(struct work_struct *work)
  93{
  94        struct rcar_gen3_chan *ch = container_of(work, struct rcar_gen3_chan,
  95                                                 work);
  96
  97        if (ch->extcon_host) {
  98                extcon_set_state_sync(ch->extcon, EXTCON_USB_HOST, true);
  99                extcon_set_state_sync(ch->extcon, EXTCON_USB, false);
 100        } else {
 101                extcon_set_state_sync(ch->extcon, EXTCON_USB_HOST, false);
 102                extcon_set_state_sync(ch->extcon, EXTCON_USB, true);
 103        }
 104}
 105
 106static void rcar_gen3_set_host_mode(struct rcar_gen3_chan *ch, int host)
 107{
 108        void __iomem *usb2_base = ch->base;
 109        u32 val = readl(usb2_base + USB2_COMMCTRL);
 110
 111        dev_vdbg(&ch->phy->dev, "%s: %08x, %d\n", __func__, val, host);
 112        if (host)
 113                val &= ~USB2_COMMCTRL_OTG_PERI;
 114        else
 115                val |= USB2_COMMCTRL_OTG_PERI;
 116        writel(val, usb2_base + USB2_COMMCTRL);
 117}
 118
 119static void rcar_gen3_set_linectrl(struct rcar_gen3_chan *ch, int dp, int dm)
 120{
 121        void __iomem *usb2_base = ch->base;
 122        u32 val = readl(usb2_base + USB2_LINECTRL1);
 123
 124        dev_vdbg(&ch->phy->dev, "%s: %08x, %d, %d\n", __func__, val, dp, dm);
 125        val &= ~(USB2_LINECTRL1_DP_RPD | USB2_LINECTRL1_DM_RPD);
 126        if (dp)
 127                val |= USB2_LINECTRL1_DP_RPD;
 128        if (dm)
 129                val |= USB2_LINECTRL1_DM_RPD;
 130        writel(val, usb2_base + USB2_LINECTRL1);
 131}
 132
 133static void rcar_gen3_enable_vbus_ctrl(struct rcar_gen3_chan *ch, int vbus)
 134{
 135        void __iomem *usb2_base = ch->base;
 136        u32 val = readl(usb2_base + USB2_ADPCTRL);
 137
 138        dev_vdbg(&ch->phy->dev, "%s: %08x, %d\n", __func__, val, vbus);
 139        if (vbus)
 140                val |= USB2_ADPCTRL_DRVVBUS;
 141        else
 142                val &= ~USB2_ADPCTRL_DRVVBUS;
 143        writel(val, usb2_base + USB2_ADPCTRL);
 144}
 145
 146static void rcar_gen3_init_for_host(struct rcar_gen3_chan *ch)
 147{
 148        rcar_gen3_set_linectrl(ch, 1, 1);
 149        rcar_gen3_set_host_mode(ch, 1);
 150        rcar_gen3_enable_vbus_ctrl(ch, 1);
 151
 152        ch->extcon_host = true;
 153        schedule_work(&ch->work);
 154}
 155
 156static void rcar_gen3_init_for_peri(struct rcar_gen3_chan *ch)
 157{
 158        rcar_gen3_set_linectrl(ch, 0, 1);
 159        rcar_gen3_set_host_mode(ch, 0);
 160        rcar_gen3_enable_vbus_ctrl(ch, 0);
 161
 162        ch->extcon_host = false;
 163        schedule_work(&ch->work);
 164}
 165
 166static void rcar_gen3_init_for_b_host(struct rcar_gen3_chan *ch)
 167{
 168        void __iomem *usb2_base = ch->base;
 169        u32 val;
 170
 171        val = readl(usb2_base + USB2_LINECTRL1);
 172        writel(val | USB2_LINECTRL1_OPMODE_NODRV, usb2_base + USB2_LINECTRL1);
 173
 174        rcar_gen3_set_linectrl(ch, 1, 1);
 175        rcar_gen3_set_host_mode(ch, 1);
 176        rcar_gen3_enable_vbus_ctrl(ch, 0);
 177
 178        val = readl(usb2_base + USB2_LINECTRL1);
 179        writel(val & ~USB2_LINECTRL1_OPMODE_NODRV, usb2_base + USB2_LINECTRL1);
 180}
 181
 182static void rcar_gen3_init_for_a_peri(struct rcar_gen3_chan *ch)
 183{
 184        rcar_gen3_set_linectrl(ch, 0, 1);
 185        rcar_gen3_set_host_mode(ch, 0);
 186        rcar_gen3_enable_vbus_ctrl(ch, 1);
 187}
 188
 189static void rcar_gen3_init_from_a_peri_to_a_host(struct rcar_gen3_chan *ch)
 190{
 191        void __iomem *usb2_base = ch->base;
 192        u32 val;
 193
 194        val = readl(usb2_base + USB2_OBINTEN);
 195        writel(val & ~USB2_OBINT_BITS, usb2_base + USB2_OBINTEN);
 196
 197        rcar_gen3_enable_vbus_ctrl(ch, 0);
 198        rcar_gen3_init_for_host(ch);
 199
 200        writel(val | USB2_OBINT_BITS, usb2_base + USB2_OBINTEN);
 201}
 202
 203static bool rcar_gen3_check_id(struct rcar_gen3_chan *ch)
 204{
 205        return !!(readl(ch->base + USB2_ADPCTRL) & USB2_ADPCTRL_IDDIG);
 206}
 207
 208static void rcar_gen3_device_recognition(struct rcar_gen3_chan *ch)
 209{
 210        if (!rcar_gen3_check_id(ch))
 211                rcar_gen3_init_for_host(ch);
 212        else
 213                rcar_gen3_init_for_peri(ch);
 214}
 215
 216static bool rcar_gen3_is_host(struct rcar_gen3_chan *ch)
 217{
 218        return !(readl(ch->base + USB2_COMMCTRL) & USB2_COMMCTRL_OTG_PERI);
 219}
 220
 221static ssize_t role_store(struct device *dev, struct device_attribute *attr,
 222                          const char *buf, size_t count)
 223{
 224        struct rcar_gen3_chan *ch = dev_get_drvdata(dev);
 225        bool is_b_device, is_host, new_mode_is_host;
 226
 227        if (!ch->has_otg || !ch->phy->init_count)
 228                return -EIO;
 229
 230        /*
 231         * is_b_device: true is B-Device. false is A-Device.
 232         * If {new_mode_}is_host: true is Host mode. false is Peripheral mode.
 233         */
 234        is_b_device = rcar_gen3_check_id(ch);
 235        is_host = rcar_gen3_is_host(ch);
 236        if (!strncmp(buf, "host", strlen("host")))
 237                new_mode_is_host = true;
 238        else if (!strncmp(buf, "peripheral", strlen("peripheral")))
 239                new_mode_is_host = false;
 240        else
 241                return -EINVAL;
 242
 243        /* If current and new mode is the same, this returns the error */
 244        if (is_host == new_mode_is_host)
 245                return -EINVAL;
 246
 247        if (new_mode_is_host) {         /* And is_host must be false */
 248                if (!is_b_device)       /* A-Peripheral */
 249                        rcar_gen3_init_from_a_peri_to_a_host(ch);
 250                else                    /* B-Peripheral */
 251                        rcar_gen3_init_for_b_host(ch);
 252        } else {                        /* And is_host must be true */
 253                if (!is_b_device)       /* A-Host */
 254                        rcar_gen3_init_for_a_peri(ch);
 255                else                    /* B-Host */
 256                        rcar_gen3_init_for_peri(ch);
 257        }
 258
 259        return count;
 260}
 261
 262static ssize_t role_show(struct device *dev, struct device_attribute *attr,
 263                         char *buf)
 264{
 265        struct rcar_gen3_chan *ch = dev_get_drvdata(dev);
 266
 267        if (!ch->has_otg || !ch->phy->init_count)
 268                return -EIO;
 269
 270        return sprintf(buf, "%s\n", rcar_gen3_is_host(ch) ? "host" :
 271                                                            "peripheral");
 272}
 273static DEVICE_ATTR_RW(role);
 274
 275static void rcar_gen3_init_otg(struct rcar_gen3_chan *ch)
 276{
 277        void __iomem *usb2_base = ch->base;
 278        u32 val;
 279
 280        val = readl(usb2_base + USB2_VBCTRL);
 281        writel(val | USB2_VBCTRL_DRVVBUSSEL, usb2_base + USB2_VBCTRL);
 282        writel(USB2_OBINT_BITS, usb2_base + USB2_OBINTSTA);
 283        val = readl(usb2_base + USB2_OBINTEN);
 284        writel(val | USB2_OBINT_BITS, usb2_base + USB2_OBINTEN);
 285        val = readl(usb2_base + USB2_ADPCTRL);
 286        writel(val | USB2_ADPCTRL_IDPULLUP, usb2_base + USB2_ADPCTRL);
 287        val = readl(usb2_base + USB2_LINECTRL1);
 288        rcar_gen3_set_linectrl(ch, 0, 0);
 289        writel(val | USB2_LINECTRL1_DPRPD_EN | USB2_LINECTRL1_DMRPD_EN,
 290               usb2_base + USB2_LINECTRL1);
 291
 292        rcar_gen3_device_recognition(ch);
 293}
 294
 295static int rcar_gen3_phy_usb2_init(struct phy *p)
 296{
 297        struct rcar_gen3_chan *channel = phy_get_drvdata(p);
 298        void __iomem *usb2_base = channel->base;
 299
 300        /* Initialize USB2 part */
 301        writel(USB2_INT_ENABLE_INIT, usb2_base + USB2_INT_ENABLE);
 302        writel(USB2_SPD_RSM_TIMSET_INIT, usb2_base + USB2_SPD_RSM_TIMSET);
 303        writel(USB2_OC_TIMSET_INIT, usb2_base + USB2_OC_TIMSET);
 304
 305        /* Initialize otg part */
 306        if (channel->has_otg)
 307                rcar_gen3_init_otg(channel);
 308
 309        return 0;
 310}
 311
 312static int rcar_gen3_phy_usb2_exit(struct phy *p)
 313{
 314        struct rcar_gen3_chan *channel = phy_get_drvdata(p);
 315
 316        writel(0, channel->base + USB2_INT_ENABLE);
 317
 318        return 0;
 319}
 320
 321static int rcar_gen3_phy_usb2_power_on(struct phy *p)
 322{
 323        struct rcar_gen3_chan *channel = phy_get_drvdata(p);
 324        void __iomem *usb2_base = channel->base;
 325        u32 val;
 326        int ret;
 327
 328        if (channel->vbus) {
 329                ret = regulator_enable(channel->vbus);
 330                if (ret)
 331                        return ret;
 332        }
 333
 334        val = readl(usb2_base + USB2_USBCTR);
 335        val |= USB2_USBCTR_PLL_RST;
 336        writel(val, usb2_base + USB2_USBCTR);
 337        val &= ~USB2_USBCTR_PLL_RST;
 338        writel(val, usb2_base + USB2_USBCTR);
 339
 340        return 0;
 341}
 342
 343static int rcar_gen3_phy_usb2_power_off(struct phy *p)
 344{
 345        struct rcar_gen3_chan *channel = phy_get_drvdata(p);
 346        int ret = 0;
 347
 348        if (channel->vbus)
 349                ret = regulator_disable(channel->vbus);
 350
 351        return ret;
 352}
 353
 354static const struct phy_ops rcar_gen3_phy_usb2_ops = {
 355        .init           = rcar_gen3_phy_usb2_init,
 356        .exit           = rcar_gen3_phy_usb2_exit,
 357        .power_on       = rcar_gen3_phy_usb2_power_on,
 358        .power_off      = rcar_gen3_phy_usb2_power_off,
 359        .owner          = THIS_MODULE,
 360};
 361
 362static irqreturn_t rcar_gen3_phy_usb2_irq(int irq, void *_ch)
 363{
 364        struct rcar_gen3_chan *ch = _ch;
 365        void __iomem *usb2_base = ch->base;
 366        u32 status = readl(usb2_base + USB2_OBINTSTA);
 367        irqreturn_t ret = IRQ_NONE;
 368
 369        if (status & USB2_OBINT_BITS) {
 370                dev_vdbg(&ch->phy->dev, "%s: %08x\n", __func__, status);
 371                writel(USB2_OBINT_BITS, usb2_base + USB2_OBINTSTA);
 372                rcar_gen3_device_recognition(ch);
 373                ret = IRQ_HANDLED;
 374        }
 375
 376        return ret;
 377}
 378
 379static const struct of_device_id rcar_gen3_phy_usb2_match_table[] = {
 380        { .compatible = "renesas,usb2-phy-r8a7795" },
 381        { .compatible = "renesas,usb2-phy-r8a7796" },
 382        { .compatible = "renesas,rcar-gen3-usb2-phy" },
 383        { }
 384};
 385MODULE_DEVICE_TABLE(of, rcar_gen3_phy_usb2_match_table);
 386
 387static const unsigned int rcar_gen3_phy_cable[] = {
 388        EXTCON_USB,
 389        EXTCON_USB_HOST,
 390        EXTCON_NONE,
 391};
 392
 393static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev)
 394{
 395        struct device *dev = &pdev->dev;
 396        struct rcar_gen3_chan *channel;
 397        struct phy_provider *provider;
 398        struct resource *res;
 399        int irq, ret = 0;
 400
 401        if (!dev->of_node) {
 402                dev_err(dev, "This driver needs device tree\n");
 403                return -EINVAL;
 404        }
 405
 406        channel = devm_kzalloc(dev, sizeof(*channel), GFP_KERNEL);
 407        if (!channel)
 408                return -ENOMEM;
 409
 410        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 411        channel->base = devm_ioremap_resource(dev, res);
 412        if (IS_ERR(channel->base))
 413                return PTR_ERR(channel->base);
 414
 415        /* call request_irq for OTG */
 416        irq = platform_get_irq(pdev, 0);
 417        if (irq >= 0) {
 418                int ret;
 419
 420                INIT_WORK(&channel->work, rcar_gen3_phy_usb2_work);
 421                irq = devm_request_irq(dev, irq, rcar_gen3_phy_usb2_irq,
 422                                       IRQF_SHARED, dev_name(dev), channel);
 423                if (irq < 0)
 424                        dev_err(dev, "No irq handler (%d)\n", irq);
 425                channel->has_otg = true;
 426                channel->extcon = devm_extcon_dev_allocate(dev,
 427                                                        rcar_gen3_phy_cable);
 428                if (IS_ERR(channel->extcon))
 429                        return PTR_ERR(channel->extcon);
 430
 431                ret = devm_extcon_dev_register(dev, channel->extcon);
 432                if (ret < 0) {
 433                        dev_err(dev, "Failed to register extcon\n");
 434                        return ret;
 435                }
 436        }
 437
 438        /*
 439         * devm_phy_create() will call pm_runtime_enable(&phy->dev);
 440         * And then, phy-core will manage runtime pm for this device.
 441         */
 442        pm_runtime_enable(dev);
 443        channel->phy = devm_phy_create(dev, NULL, &rcar_gen3_phy_usb2_ops);
 444        if (IS_ERR(channel->phy)) {
 445                dev_err(dev, "Failed to create USB2 PHY\n");
 446                ret = PTR_ERR(channel->phy);
 447                goto error;
 448        }
 449
 450        channel->vbus = devm_regulator_get_optional(dev, "vbus");
 451        if (IS_ERR(channel->vbus)) {
 452                if (PTR_ERR(channel->vbus) == -EPROBE_DEFER) {
 453                        ret = PTR_ERR(channel->vbus);
 454                        goto error;
 455                }
 456                channel->vbus = NULL;
 457        }
 458
 459        platform_set_drvdata(pdev, channel);
 460        phy_set_drvdata(channel->phy, channel);
 461
 462        provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
 463        if (IS_ERR(provider)) {
 464                dev_err(dev, "Failed to register PHY provider\n");
 465                ret = PTR_ERR(provider);
 466                goto error;
 467        } else if (channel->has_otg) {
 468                int ret;
 469
 470                ret = device_create_file(dev, &dev_attr_role);
 471                if (ret < 0)
 472                        goto error;
 473        }
 474
 475        return 0;
 476
 477error:
 478        pm_runtime_disable(dev);
 479
 480        return ret;
 481}
 482
 483static int rcar_gen3_phy_usb2_remove(struct platform_device *pdev)
 484{
 485        struct rcar_gen3_chan *channel = platform_get_drvdata(pdev);
 486
 487        if (channel->has_otg)
 488                device_remove_file(&pdev->dev, &dev_attr_role);
 489
 490        pm_runtime_disable(&pdev->dev);
 491
 492        return 0;
 493};
 494
 495static struct platform_driver rcar_gen3_phy_usb2_driver = {
 496        .driver = {
 497                .name           = "phy_rcar_gen3_usb2",
 498                .of_match_table = rcar_gen3_phy_usb2_match_table,
 499        },
 500        .probe  = rcar_gen3_phy_usb2_probe,
 501        .remove = rcar_gen3_phy_usb2_remove,
 502};
 503module_platform_driver(rcar_gen3_phy_usb2_driver);
 504
 505MODULE_LICENSE("GPL v2");
 506MODULE_DESCRIPTION("Renesas R-Car Gen3 USB 2.0 PHY");
 507MODULE_AUTHOR("Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>");
 508