1 // SPDX-License-Identifier: GPL-2.0
3 * Renesas R-Car Gen3 PCIe PHY driver
5 * Copyright (C) 2018 Cogent Embedded, Inc.
10 #include <linux/module.h>
12 #include <linux/phy/phy.h>
13 #include <linux/of_device.h>
14 #include <linux/platform_device.h>
15 #include <linux/spinlock.h>
17 #define PHY_CTRL 0x4000 /* R8A77980 only */
19 /* PHY control register (PHY_CTRL) */
20 #define PHY_CTRL_PHY_PWDN BIT(2)
22 struct rcar_gen3_phy
{
28 static void rcar_gen3_phy_pcie_modify_reg(struct phy
*p
, unsigned int reg
,
31 struct rcar_gen3_phy
*phy
= phy_get_drvdata(p
);
32 void __iomem
*base
= phy
->base
;
36 spin_lock_irqsave(&phy
->lock
, flags
);
38 value
= readl(base
+ reg
);
41 writel(value
, base
+ reg
);
43 spin_unlock_irqrestore(&phy
->lock
, flags
);
46 static int r8a77980_phy_pcie_power_on(struct phy
*p
)
48 /* Power on the PCIe PHY */
49 rcar_gen3_phy_pcie_modify_reg(p
, PHY_CTRL
, PHY_CTRL_PHY_PWDN
, 0);
54 static int r8a77980_phy_pcie_power_off(struct phy
*p
)
56 /* Power off the PCIe PHY */
57 rcar_gen3_phy_pcie_modify_reg(p
, PHY_CTRL
, 0, PHY_CTRL_PHY_PWDN
);
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
,
68 static const struct of_device_id rcar_gen3_phy_pcie_match_table
[] = {
69 { .compatible
= "renesas,r8a77980-pcie-phy" },
72 MODULE_DEVICE_TABLE(of
, rcar_gen3_phy_pcie_match_table
);
74 static int rcar_gen3_phy_pcie_probe(struct platform_device
*pdev
)
76 struct device
*dev
= &pdev
->dev
;
77 struct phy_provider
*provider
;
78 struct rcar_gen3_phy
*phy
;
85 "This driver must only be instantiated from the device tree\n");
89 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
90 base
= devm_ioremap_resource(dev
, res
);
94 phy
= devm_kzalloc(dev
, sizeof(*phy
), GFP_KERNEL
);
98 spin_lock_init(&phy
->lock
);
103 * devm_phy_create() will call pm_runtime_enable(&phy->dev);
104 * And then, phy-core will manage runtime PM for this device.
106 pm_runtime_enable(dev
);
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
);
114 phy_set_drvdata(phy
->phy
, phy
);
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
);
126 pm_runtime_disable(dev
);
131 static int rcar_gen3_phy_pcie_remove(struct platform_device
*pdev
)
133 pm_runtime_disable(&pdev
->dev
);
138 static struct platform_driver rcar_gen3_phy_driver
= {
140 .name
= "phy_rcar_gen3_pcie",
141 .of_match_table
= rcar_gen3_phy_pcie_match_table
,
143 .probe
= rcar_gen3_phy_pcie_probe
,
144 .remove
= rcar_gen3_phy_pcie_remove
,
147 module_platform_driver(rcar_gen3_phy_driver
);
149 MODULE_LICENSE("GPL v2");
150 MODULE_DESCRIPTION("Renesas R-Car Gen3 PCIe PHY");
151 MODULE_AUTHOR("Sergei Shtylyov <sergei.shtylyov@cogentembedded.com>");