1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Amlogic AXG MIPI + PCIE analog PHY driver 4 * 5 * Copyright (C) 2019 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/platform_device.h> 11 #include <dt-bindings/phy/phy.h> 12 13 #define HHI_MIPI_CNTL0 0x00 14 #define HHI_MIPI_CNTL0_COMMON_BLOCK GENMASK(31, 28) 15 #define HHI_MIPI_CNTL0_ENABLE BIT(29) 16 #define HHI_MIPI_CNTL0_BANDGAP BIT(26) 17 #define HHI_MIPI_CNTL0_DECODE_TO_RTERM GENMASK(15, 12) 18 #define HHI_MIPI_CNTL0_OUTPUT_EN BIT(3) 19 20 #define HHI_MIPI_CNTL1 0x01 21 #define HHI_MIPI_CNTL1_CH0_CML_PDR_EN BIT(12) 22 #define HHI_MIPI_CNTL1_LP_ABILITY GENMASK(5, 4) 23 #define HHI_MIPI_CNTL1_LP_RESISTER BIT(3) 24 #define HHI_MIPI_CNTL1_INPUT_SETTING BIT(2) 25 #define HHI_MIPI_CNTL1_INPUT_SEL BIT(1) 26 #define HHI_MIPI_CNTL1_PRBS7_EN BIT(0) 27 28 #define HHI_MIPI_CNTL2 0x02 29 #define HHI_MIPI_CNTL2_CH_PU GENMASK(31, 25) 30 #define HHI_MIPI_CNTL2_CH_CTL GENMASK(24, 19) 31 #define HHI_MIPI_CNTL2_CH0_DIGDR_EN BIT(18) 32 #define HHI_MIPI_CNTL2_CH_DIGDR_EN BIT(17) 33 #define HHI_MIPI_CNTL2_LPULPS_EN BIT(16) 34 #define HHI_MIPI_CNTL2_CH_EN(n) BIT(15 - (n)) 35 #define HHI_MIPI_CNTL2_CH0_LP_CTL GENMASK(10, 1) 36 37 struct phy_axg_mipi_pcie_analog_priv { 38 struct phy *phy; 39 unsigned int mode; 40 struct regmap *regmap; 41 }; 42 43 static const struct regmap_config phy_axg_mipi_pcie_analog_regmap_conf = { 44 .reg_bits = 8, 45 .val_bits = 32, 46 .reg_stride = 4, 47 .max_register = HHI_MIPI_CNTL2, 48 }; 49 50 static int phy_axg_mipi_pcie_analog_power_on(struct phy *phy) 51 { 52 struct phy_axg_mipi_pcie_analog_priv *priv = phy_get_drvdata(phy); 53 54 /* MIPI not supported yet */ 55 if (priv->mode != PHY_TYPE_PCIE) 56 return -EINVAL; 57 58 regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0, 59 HHI_MIPI_CNTL0_BANDGAP, HHI_MIPI_CNTL0_BANDGAP); 60 61 regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0, 62 HHI_MIPI_CNTL0_ENABLE, HHI_MIPI_CNTL0_ENABLE); 63 return 0; 64 } 65 66 static int phy_axg_mipi_pcie_analog_power_off(struct phy *phy) 67 { 68 struct phy_axg_mipi_pcie_analog_priv *priv = phy_get_drvdata(phy); 69 70 /* MIPI not supported yet */ 71 if (priv->mode != PHY_TYPE_PCIE) 72 return -EINVAL; 73 74 regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0, 75 HHI_MIPI_CNTL0_BANDGAP, 0); 76 regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0, 77 HHI_MIPI_CNTL0_ENABLE, 0); 78 return 0; 79 } 80 81 static int phy_axg_mipi_pcie_analog_init(struct phy *phy) 82 { 83 return 0; 84 } 85 86 static int phy_axg_mipi_pcie_analog_exit(struct phy *phy) 87 { 88 return 0; 89 } 90 91 static const struct phy_ops phy_axg_mipi_pcie_analog_ops = { 92 .init = phy_axg_mipi_pcie_analog_init, 93 .exit = phy_axg_mipi_pcie_analog_exit, 94 .power_on = phy_axg_mipi_pcie_analog_power_on, 95 .power_off = phy_axg_mipi_pcie_analog_power_off, 96 .owner = THIS_MODULE, 97 }; 98 99 static struct phy *phy_axg_mipi_pcie_analog_xlate(struct device *dev, 100 struct of_phandle_args *args) 101 { 102 struct phy_axg_mipi_pcie_analog_priv *priv = dev_get_drvdata(dev); 103 unsigned int mode; 104 105 if (args->args_count != 1) { 106 dev_err(dev, "invalid number of arguments\n"); 107 return ERR_PTR(-EINVAL); 108 } 109 110 mode = args->args[0]; 111 112 /* MIPI mode is not supported yet */ 113 if (mode != PHY_TYPE_PCIE) { 114 dev_err(dev, "invalid phy mode select argument\n"); 115 return ERR_PTR(-EINVAL); 116 } 117 118 priv->mode = mode; 119 return priv->phy; 120 } 121 122 static int phy_axg_mipi_pcie_analog_probe(struct platform_device *pdev) 123 { 124 struct phy_provider *phy; 125 struct device *dev = &pdev->dev; 126 struct phy_axg_mipi_pcie_analog_priv *priv; 127 struct device_node *np = dev->of_node; 128 struct regmap *map; 129 struct resource *res; 130 void __iomem *base; 131 int ret; 132 133 priv = devm_kmalloc(dev, sizeof(*priv), GFP_KERNEL); 134 if (!priv) 135 return -ENOMEM; 136 137 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 138 base = devm_ioremap_resource(dev, res); 139 if (IS_ERR(base)) { 140 dev_err(dev, "failed to get regmap base\n"); 141 return PTR_ERR(base); 142 } 143 144 map = devm_regmap_init_mmio(dev, base, 145 &phy_axg_mipi_pcie_analog_regmap_conf); 146 if (IS_ERR(map)) { 147 dev_err(dev, "failed to get HHI regmap\n"); 148 return PTR_ERR(map); 149 } 150 priv->regmap = map; 151 152 priv->phy = devm_phy_create(dev, np, &phy_axg_mipi_pcie_analog_ops); 153 if (IS_ERR(priv->phy)) { 154 ret = PTR_ERR(priv->phy); 155 if (ret != -EPROBE_DEFER) 156 dev_err(dev, "failed to create PHY\n"); 157 return ret; 158 } 159 160 phy_set_drvdata(priv->phy, priv); 161 dev_set_drvdata(dev, priv); 162 163 phy = devm_of_phy_provider_register(dev, 164 phy_axg_mipi_pcie_analog_xlate); 165 166 return PTR_ERR_OR_ZERO(phy); 167 } 168 169 static const struct of_device_id phy_axg_mipi_pcie_analog_of_match[] = { 170 { 171 .compatible = "amlogic,axg-mipi-pcie-analog-phy", 172 }, 173 { }, 174 }; 175 MODULE_DEVICE_TABLE(of, phy_axg_mipi_pcie_analog_of_match); 176 177 static struct platform_driver phy_axg_mipi_pcie_analog_driver = { 178 .probe = phy_axg_mipi_pcie_analog_probe, 179 .driver = { 180 .name = "phy-axg-mipi-pcie-analog", 181 .of_match_table = phy_axg_mipi_pcie_analog_of_match, 182 }, 183 }; 184 module_platform_driver(phy_axg_mipi_pcie_analog_driver); 185 186 MODULE_AUTHOR("Remi Pommarel <repk@triplefau.lt>"); 187 MODULE_DESCRIPTION("Amlogic AXG MIPI + PCIE analog PHY driver"); 188 MODULE_LICENSE("GPL v2"); 189