1 // SPDX-License-Identifier: GPL-2.0
3 * Amlogic AXG MIPI + PCIE analog PHY driver
5 * Copyright (C) 2019 Remi Pommarel <repk@triplefau.lt>
7 #include <linux/bitfield.h>
8 #include <linux/bitops.h>
9 #include <linux/module.h>
10 #include <linux/phy/phy.h>
11 #include <linux/regmap.h>
12 #include <linux/delay.h>
13 #include <linux/mfd/syscon.h>
15 #include <linux/platform_device.h>
16 #include <dt-bindings/phy/phy.h>
18 #define HHI_MIPI_CNTL0 0x00
19 #define HHI_MIPI_CNTL0_COMMON_BLOCK GENMASK(31, 28)
20 #define HHI_MIPI_CNTL0_ENABLE BIT(29)
21 #define HHI_MIPI_CNTL0_BANDGAP BIT(26)
22 #define HHI_MIPI_CNTL0_DIF_REF_CTL1 GENMASK(25, 16)
23 #define HHI_MIPI_CNTL0_DIF_REF_CTL0 GENMASK(15, 0)
25 #define HHI_MIPI_CNTL1 0x04
26 #define HHI_MIPI_CNTL1_CH0_CML_PDR_EN BIT(12)
27 #define HHI_MIPI_CNTL1_LP_ABILITY GENMASK(5, 4)
28 #define HHI_MIPI_CNTL1_LP_RESISTER BIT(3)
29 #define HHI_MIPI_CNTL1_INPUT_SETTING BIT(2)
30 #define HHI_MIPI_CNTL1_INPUT_SEL BIT(1)
31 #define HHI_MIPI_CNTL1_PRBS7_EN BIT(0)
33 #define HHI_MIPI_CNTL2 0x08
34 #define HHI_MIPI_CNTL2_CH_PU GENMASK(31, 25)
35 #define HHI_MIPI_CNTL2_CH_CTL GENMASK(24, 19)
36 #define HHI_MIPI_CNTL2_CH0_DIGDR_EN BIT(18)
37 #define HHI_MIPI_CNTL2_CH_DIGDR_EN BIT(17)
38 #define HHI_MIPI_CNTL2_LPULPS_EN BIT(16)
39 #define HHI_MIPI_CNTL2_CH_EN GENMASK(15, 11)
40 #define HHI_MIPI_CNTL2_CH0_LP_CTL GENMASK(10, 1)
42 #define DSI_LANE_0 BIT(4)
43 #define DSI_LANE_1 BIT(3)
44 #define DSI_LANE_CLK BIT(2)
45 #define DSI_LANE_2 BIT(1)
46 #define DSI_LANE_3 BIT(0)
48 struct phy_axg_mipi_pcie_analog_priv
{
50 struct regmap
*regmap
;
54 struct phy_configure_opts_mipi_dphy config
;
57 static void phy_bandgap_enable(struct phy_axg_mipi_pcie_analog_priv
*priv
)
59 regmap_update_bits(priv
->regmap
, HHI_MIPI_CNTL0
,
60 HHI_MIPI_CNTL0_BANDGAP
, HHI_MIPI_CNTL0_BANDGAP
);
62 regmap_update_bits(priv
->regmap
, HHI_MIPI_CNTL0
,
63 HHI_MIPI_CNTL0_ENABLE
, HHI_MIPI_CNTL0_ENABLE
);
66 static void phy_bandgap_disable(struct phy_axg_mipi_pcie_analog_priv
*priv
)
68 regmap_update_bits(priv
->regmap
, HHI_MIPI_CNTL0
,
69 HHI_MIPI_CNTL0_BANDGAP
, 0);
70 regmap_update_bits(priv
->regmap
, HHI_MIPI_CNTL0
,
71 HHI_MIPI_CNTL0_ENABLE
, 0);
74 static void phy_dsi_analog_enable(struct phy_axg_mipi_pcie_analog_priv
*priv
)
78 regmap_update_bits(priv
->regmap
, HHI_MIPI_CNTL0
,
79 HHI_MIPI_CNTL0_DIF_REF_CTL1
,
80 FIELD_PREP(HHI_MIPI_CNTL0_DIF_REF_CTL1
, 0x1b8));
81 regmap_update_bits(priv
->regmap
, HHI_MIPI_CNTL0
,
83 regmap_update_bits(priv
->regmap
, HHI_MIPI_CNTL0
,
84 HHI_MIPI_CNTL0_DIF_REF_CTL0
,
85 FIELD_PREP(HHI_MIPI_CNTL0_DIF_REF_CTL0
, 0x8));
87 regmap_write(priv
->regmap
, HHI_MIPI_CNTL1
, 0x001e);
89 regmap_write(priv
->regmap
, HHI_MIPI_CNTL2
,
90 (0x26e0 << 16) | (0x459 << 0));
93 switch (priv
->config
.lanes
) {
110 regmap_update_bits(priv
->regmap
, HHI_MIPI_CNTL2
,
111 HHI_MIPI_CNTL2_CH_EN
,
112 FIELD_PREP(HHI_MIPI_CNTL2_CH_EN
, reg
));
114 priv
->dsi_enabled
= true;
117 static void phy_dsi_analog_disable(struct phy_axg_mipi_pcie_analog_priv
*priv
)
119 regmap_update_bits(priv
->regmap
, HHI_MIPI_CNTL0
,
120 HHI_MIPI_CNTL0_DIF_REF_CTL1
,
121 FIELD_PREP(HHI_MIPI_CNTL0_DIF_REF_CTL1
, 0));
122 regmap_update_bits(priv
->regmap
, HHI_MIPI_CNTL0
, BIT(31), 0);
123 regmap_update_bits(priv
->regmap
, HHI_MIPI_CNTL0
,
124 HHI_MIPI_CNTL0_DIF_REF_CTL1
, 0);
126 regmap_write(priv
->regmap
, HHI_MIPI_CNTL1
, 0x6);
128 regmap_write(priv
->regmap
, HHI_MIPI_CNTL2
, 0x00200000);
130 priv
->dsi_enabled
= false;
133 static int phy_axg_mipi_pcie_analog_configure(struct phy
*phy
,
134 union phy_configure_opts
*opts
)
136 struct phy_axg_mipi_pcie_analog_priv
*priv
= phy_get_drvdata(phy
);
139 ret
= phy_mipi_dphy_config_validate(&opts
->mipi_dphy
);
143 memcpy(&priv
->config
, opts
, sizeof(priv
->config
));
145 priv
->dsi_configured
= true;
147 /* If PHY was already powered on, setup the DSI analog part */
149 /* If reconfiguring, disable & reconfigure */
150 if (priv
->dsi_enabled
)
151 phy_dsi_analog_disable(priv
);
153 usleep_range(100, 200);
155 phy_dsi_analog_enable(priv
);
161 static int phy_axg_mipi_pcie_analog_power_on(struct phy
*phy
)
163 struct phy_axg_mipi_pcie_analog_priv
*priv
= phy_get_drvdata(phy
);
165 phy_bandgap_enable(priv
);
167 if (priv
->dsi_configured
)
168 phy_dsi_analog_enable(priv
);
170 priv
->powered
= true;
175 static int phy_axg_mipi_pcie_analog_power_off(struct phy
*phy
)
177 struct phy_axg_mipi_pcie_analog_priv
*priv
= phy_get_drvdata(phy
);
179 phy_bandgap_disable(priv
);
181 if (priv
->dsi_enabled
)
182 phy_dsi_analog_disable(priv
);
184 priv
->powered
= false;
189 static const struct phy_ops phy_axg_mipi_pcie_analog_ops
= {
190 .configure
= phy_axg_mipi_pcie_analog_configure
,
191 .power_on
= phy_axg_mipi_pcie_analog_power_on
,
192 .power_off
= phy_axg_mipi_pcie_analog_power_off
,
193 .owner
= THIS_MODULE
,
196 static int phy_axg_mipi_pcie_analog_probe(struct platform_device
*pdev
)
198 struct phy_provider
*phy
;
199 struct device
*dev
= &pdev
->dev
;
200 struct phy_axg_mipi_pcie_analog_priv
*priv
;
201 struct device_node
*np
= dev
->of_node
, *parent_np
;
205 priv
= devm_kmalloc(dev
, sizeof(*priv
), GFP_KERNEL
);
209 /* Get the hhi system controller node */
210 parent_np
= of_get_parent(dev
->of_node
);
211 map
= syscon_node_to_regmap(parent_np
);
212 of_node_put(parent_np
);
215 "failed to get HHI regmap\n");
221 priv
->phy
= devm_phy_create(dev
, np
, &phy_axg_mipi_pcie_analog_ops
);
222 if (IS_ERR(priv
->phy
)) {
223 ret
= PTR_ERR(priv
->phy
);
224 if (ret
!= -EPROBE_DEFER
)
225 dev_err(dev
, "failed to create PHY\n");
229 phy_set_drvdata(priv
->phy
, priv
);
230 dev_set_drvdata(dev
, priv
);
232 phy
= devm_of_phy_provider_register(dev
, of_phy_simple_xlate
);
234 return PTR_ERR_OR_ZERO(phy
);
237 static const struct of_device_id phy_axg_mipi_pcie_analog_of_match
[] = {
239 .compatible
= "amlogic,axg-mipi-pcie-analog-phy",
243 MODULE_DEVICE_TABLE(of
, phy_axg_mipi_pcie_analog_of_match
);
245 static struct platform_driver phy_axg_mipi_pcie_analog_driver
= {
246 .probe
= phy_axg_mipi_pcie_analog_probe
,
248 .name
= "phy-axg-mipi-pcie-analog",
249 .of_match_table
= phy_axg_mipi_pcie_analog_of_match
,
252 module_platform_driver(phy_axg_mipi_pcie_analog_driver
);
254 MODULE_AUTHOR("Remi Pommarel <repk@triplefau.lt>");
255 MODULE_DESCRIPTION("Amlogic AXG MIPI + PCIE analog PHY driver");
256 MODULE_LICENSE("GPL v2");