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