phy-meson-axg-pcie.c (4424B)
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Amlogic AXG PCIE PHY driver 4 * 5 * Copyright (C) 2020 Remi Pommarel <repk@triplefau.lt> 6 */ 7#include <linux/module.h> 8#include <linux/phy/phy.h> 9#include <linux/regmap.h> 10#include <linux/reset.h> 11#include <linux/platform_device.h> 12#include <linux/bitfield.h> 13#include <dt-bindings/phy/phy.h> 14 15#define MESON_PCIE_REG0 0x00 16#define MESON_PCIE_COMMON_CLK BIT(4) 17#define MESON_PCIE_PORT_SEL GENMASK(3, 2) 18#define MESON_PCIE_CLK BIT(1) 19#define MESON_PCIE_POWERDOWN BIT(0) 20 21#define MESON_PCIE_TWO_X1 FIELD_PREP(MESON_PCIE_PORT_SEL, 0x3) 22#define MESON_PCIE_COMMON_REF_CLK FIELD_PREP(MESON_PCIE_COMMON_CLK, 0x1) 23#define MESON_PCIE_PHY_INIT (MESON_PCIE_TWO_X1 | \ 24 MESON_PCIE_COMMON_REF_CLK) 25#define MESON_PCIE_RESET_DELAY 500 26 27struct phy_axg_pcie_priv { 28 struct phy *phy; 29 struct phy *analog; 30 struct regmap *regmap; 31 struct reset_control *reset; 32}; 33 34static const struct regmap_config phy_axg_pcie_regmap_conf = { 35 .reg_bits = 8, 36 .val_bits = 32, 37 .reg_stride = 4, 38 .max_register = MESON_PCIE_REG0, 39}; 40 41static int phy_axg_pcie_power_on(struct phy *phy) 42{ 43 struct phy_axg_pcie_priv *priv = phy_get_drvdata(phy); 44 int ret; 45 46 ret = phy_power_on(priv->analog); 47 if (ret != 0) 48 return ret; 49 50 regmap_update_bits(priv->regmap, MESON_PCIE_REG0, 51 MESON_PCIE_POWERDOWN, 0); 52 return 0; 53} 54 55static int phy_axg_pcie_power_off(struct phy *phy) 56{ 57 struct phy_axg_pcie_priv *priv = phy_get_drvdata(phy); 58 int ret; 59 60 ret = phy_power_off(priv->analog); 61 if (ret != 0) 62 return ret; 63 64 regmap_update_bits(priv->regmap, MESON_PCIE_REG0, 65 MESON_PCIE_POWERDOWN, 1); 66 return 0; 67} 68 69static int phy_axg_pcie_init(struct phy *phy) 70{ 71 struct phy_axg_pcie_priv *priv = phy_get_drvdata(phy); 72 int ret; 73 74 ret = phy_init(priv->analog); 75 if (ret != 0) 76 return ret; 77 78 regmap_write(priv->regmap, MESON_PCIE_REG0, MESON_PCIE_PHY_INIT); 79 return reset_control_reset(priv->reset); 80} 81 82static int phy_axg_pcie_exit(struct phy *phy) 83{ 84 struct phy_axg_pcie_priv *priv = phy_get_drvdata(phy); 85 int ret; 86 87 ret = phy_exit(priv->analog); 88 if (ret != 0) 89 return ret; 90 91 return reset_control_reset(priv->reset); 92} 93 94static int phy_axg_pcie_reset(struct phy *phy) 95{ 96 struct phy_axg_pcie_priv *priv = phy_get_drvdata(phy); 97 int ret = 0; 98 99 ret = phy_reset(priv->analog); 100 if (ret != 0) 101 goto out; 102 103 ret = reset_control_assert(priv->reset); 104 if (ret != 0) 105 goto out; 106 udelay(MESON_PCIE_RESET_DELAY); 107 108 ret = reset_control_deassert(priv->reset); 109 if (ret != 0) 110 goto out; 111 udelay(MESON_PCIE_RESET_DELAY); 112 113out: 114 return ret; 115} 116 117static const struct phy_ops phy_axg_pcie_ops = { 118 .init = phy_axg_pcie_init, 119 .exit = phy_axg_pcie_exit, 120 .power_on = phy_axg_pcie_power_on, 121 .power_off = phy_axg_pcie_power_off, 122 .reset = phy_axg_pcie_reset, 123 .owner = THIS_MODULE, 124}; 125 126static int phy_axg_pcie_probe(struct platform_device *pdev) 127{ 128 struct phy_provider *pphy; 129 struct device *dev = &pdev->dev; 130 struct phy_axg_pcie_priv *priv; 131 struct device_node *np = dev->of_node; 132 void __iomem *base; 133 int ret; 134 135 priv = devm_kmalloc(dev, sizeof(*priv), GFP_KERNEL); 136 if (!priv) 137 return -ENOMEM; 138 139 priv->phy = devm_phy_create(dev, np, &phy_axg_pcie_ops); 140 if (IS_ERR(priv->phy)) { 141 ret = PTR_ERR(priv->phy); 142 if (ret != -EPROBE_DEFER) 143 dev_err(dev, "failed to create PHY\n"); 144 return ret; 145 } 146 147 base = devm_platform_ioremap_resource(pdev, 0); 148 if (IS_ERR(base)) 149 return PTR_ERR(base); 150 151 priv->regmap = devm_regmap_init_mmio(dev, base, 152 &phy_axg_pcie_regmap_conf); 153 if (IS_ERR(priv->regmap)) 154 return PTR_ERR(priv->regmap); 155 156 priv->reset = devm_reset_control_array_get_exclusive(dev); 157 if (IS_ERR(priv->reset)) 158 return PTR_ERR(priv->reset); 159 160 priv->analog = devm_phy_get(dev, "analog"); 161 if (IS_ERR(priv->analog)) 162 return PTR_ERR(priv->analog); 163 164 phy_set_drvdata(priv->phy, priv); 165 dev_set_drvdata(dev, priv); 166 pphy = devm_of_phy_provider_register(dev, of_phy_simple_xlate); 167 168 return PTR_ERR_OR_ZERO(pphy); 169} 170 171static const struct of_device_id phy_axg_pcie_of_match[] = { 172 { 173 .compatible = "amlogic,axg-pcie-phy", 174 }, 175 { }, 176}; 177MODULE_DEVICE_TABLE(of, phy_axg_pcie_of_match); 178 179static struct platform_driver phy_axg_pcie_driver = { 180 .probe = phy_axg_pcie_probe, 181 .driver = { 182 .name = "phy-axg-pcie", 183 .of_match_table = phy_axg_pcie_of_match, 184 }, 185}; 186module_platform_driver(phy_axg_pcie_driver); 187 188MODULE_AUTHOR("Remi Pommarel <repk@triplefau.lt>"); 189MODULE_DESCRIPTION("Amlogic AXG PCIE PHY driver"); 190MODULE_LICENSE("GPL v2");