root/drivers/phy/renesas/phy-rcar-gen3-pcie.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. rcar_gen3_phy_pcie_modify_reg
  2. r8a77980_phy_pcie_power_on
  3. r8a77980_phy_pcie_power_off
  4. rcar_gen3_phy_pcie_probe
  5. rcar_gen3_phy_pcie_remove

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * Renesas R-Car Gen3 PCIe PHY driver
   4  *
   5  * Copyright (C) 2018 Cogent Embedded, Inc.
   6  */
   7 
   8 #include <linux/clk.h>
   9 #include <linux/io.h>
  10 #include <linux/module.h>
  11 #include <linux/of.h>
  12 #include <linux/phy/phy.h>
  13 #include <linux/of_device.h>
  14 #include <linux/platform_device.h>
  15 #include <linux/spinlock.h>
  16 
  17 #define PHY_CTRL                0x4000          /* R8A77980 only */
  18 
  19 /* PHY control register (PHY_CTRL) */
  20 #define PHY_CTRL_PHY_PWDN       BIT(2)
  21 
  22 struct rcar_gen3_phy {
  23         struct phy *phy;
  24         spinlock_t lock;
  25         void __iomem *base;
  26 };
  27 
  28 static void rcar_gen3_phy_pcie_modify_reg(struct phy *p, unsigned int reg,
  29                                           u32 clear, u32 set)
  30 {
  31         struct rcar_gen3_phy *phy = phy_get_drvdata(p);
  32         void __iomem *base = phy->base;
  33         unsigned long flags;
  34         u32 value;
  35 
  36         spin_lock_irqsave(&phy->lock, flags);
  37 
  38         value = readl(base + reg);
  39         value &= ~clear;
  40         value |= set;
  41         writel(value, base + reg);
  42 
  43         spin_unlock_irqrestore(&phy->lock, flags);
  44 }
  45 
  46 static int r8a77980_phy_pcie_power_on(struct phy *p)
  47 {
  48         /* Power on the PCIe PHY */
  49         rcar_gen3_phy_pcie_modify_reg(p, PHY_CTRL, PHY_CTRL_PHY_PWDN, 0);
  50 
  51         return 0;
  52 }
  53 
  54 static int r8a77980_phy_pcie_power_off(struct phy *p)
  55 {
  56         /* Power off the PCIe PHY */
  57         rcar_gen3_phy_pcie_modify_reg(p, PHY_CTRL, 0, PHY_CTRL_PHY_PWDN);
  58 
  59         return 0;
  60 }
  61 
  62 static const struct phy_ops r8a77980_phy_pcie_ops = {
  63         .power_on       = r8a77980_phy_pcie_power_on,
  64         .power_off      = r8a77980_phy_pcie_power_off,
  65         .owner          = THIS_MODULE,
  66 };
  67 
  68 static const struct of_device_id rcar_gen3_phy_pcie_match_table[] = {
  69         { .compatible = "renesas,r8a77980-pcie-phy" },
  70         { }
  71 };
  72 MODULE_DEVICE_TABLE(of, rcar_gen3_phy_pcie_match_table);
  73 
  74 static int rcar_gen3_phy_pcie_probe(struct platform_device *pdev)
  75 {
  76         struct device *dev = &pdev->dev;
  77         struct phy_provider *provider;
  78         struct rcar_gen3_phy *phy;
  79         struct resource *res;
  80         void __iomem *base;
  81         int error;
  82 
  83         if (!dev->of_node) {
  84                 dev_err(dev,
  85                         "This driver must only be instantiated from the device tree\n");
  86                 return -EINVAL;
  87         }
  88 
  89         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  90         base = devm_ioremap_resource(dev, res);
  91         if (IS_ERR(base))
  92                 return PTR_ERR(base);
  93 
  94         phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);
  95         if (!phy)
  96                 return -ENOMEM;
  97 
  98         spin_lock_init(&phy->lock);
  99 
 100         phy->base = base;
 101 
 102         /*
 103          * devm_phy_create() will call pm_runtime_enable(&phy->dev);
 104          * And then, phy-core will manage runtime PM for this device.
 105          */
 106         pm_runtime_enable(dev);
 107 
 108         phy->phy = devm_phy_create(dev, NULL, &r8a77980_phy_pcie_ops);
 109         if (IS_ERR(phy->phy)) {
 110                 dev_err(dev, "Failed to create PCIe PHY\n");
 111                 error = PTR_ERR(phy->phy);
 112                 goto error;
 113         }
 114         phy_set_drvdata(phy->phy, phy);
 115 
 116         provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
 117         if (IS_ERR(provider)) {
 118                 dev_err(dev, "Failed to register PHY provider\n");
 119                 error = PTR_ERR(provider);
 120                 goto error;
 121         }
 122 
 123         return 0;
 124 
 125 error:
 126         pm_runtime_disable(dev);
 127 
 128         return error;
 129 }
 130 
 131 static int rcar_gen3_phy_pcie_remove(struct platform_device *pdev)
 132 {
 133         pm_runtime_disable(&pdev->dev);
 134 
 135         return 0;
 136 };
 137 
 138 static struct platform_driver rcar_gen3_phy_driver = {
 139         .driver = {
 140                 .name           = "phy_rcar_gen3_pcie",
 141                 .of_match_table = rcar_gen3_phy_pcie_match_table,
 142         },
 143         .probe  = rcar_gen3_phy_pcie_probe,
 144         .remove = rcar_gen3_phy_pcie_remove,
 145 };
 146 
 147 module_platform_driver(rcar_gen3_phy_driver);
 148 
 149 MODULE_LICENSE("GPL v2");
 150 MODULE_DESCRIPTION("Renesas R-Car Gen3 PCIe PHY");
 151 MODULE_AUTHOR("Sergei Shtylyov <sergei.shtylyov@cogentembedded.com>");

/* [<][>][^][v][top][bottom][index][help] */