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
phy_axg_mipi_pcie_analog_power_on(struct phy * phy)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
phy_axg_mipi_pcie_analog_power_off(struct phy * phy)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
phy_axg_mipi_pcie_analog_init(struct phy * phy)81 static int phy_axg_mipi_pcie_analog_init(struct phy *phy)
82 {
83 return 0;
84 }
85
phy_axg_mipi_pcie_analog_exit(struct phy * phy)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
phy_axg_mipi_pcie_analog_xlate(struct device * dev,struct of_phandle_args * args)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
phy_axg_mipi_pcie_analog_probe(struct platform_device * pdev)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