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>
14 #include <linux/platform_device.h>
15 #include <dt-bindings/phy/phy.h>
17 #define HHI_MIPI_CNTL0 0x00
18 #define HHI_MIPI_CNTL0_COMMON_BLOCK GENMASK(31, 28)
19 #define HHI_MIPI_CNTL0_ENABLE BIT(29)
20 #define HHI_MIPI_CNTL0_BANDGAP BIT(26)
21 #define HHI_MIPI_CNTL0_DIF_REF_CTL1 GENMASK(25, 16)
22 #define HHI_MIPI_CNTL0_DIF_REF_CTL0 GENMASK(15, 0)
24 #define HHI_MIPI_CNTL1 0x04
25 #define HHI_MIPI_CNTL1_CH0_CML_PDR_EN BIT(12)
26 #define HHI_MIPI_CNTL1_LP_ABILITY GENMASK(5, 4)
27 #define HHI_MIPI_CNTL1_LP_RESISTER BIT(3)
28 #define HHI_MIPI_CNTL1_INPUT_SETTING BIT(2)
29 #define HHI_MIPI_CNTL1_INPUT_SEL BIT(1)
30 #define HHI_MIPI_CNTL1_PRBS7_EN BIT(0)
32 #define HHI_MIPI_CNTL2 0x08
33 #define HHI_MIPI_CNTL2_CH_PU GENMASK(31, 25)
34 #define HHI_MIPI_CNTL2_CH_CTL GENMASK(24, 19)
35 #define HHI_MIPI_CNTL2_CH0_DIGDR_EN BIT(18)
36 #define HHI_MIPI_CNTL2_CH_DIGDR_EN BIT(17)
37 #define HHI_MIPI_CNTL2_LPULPS_EN BIT(16)
38 #define HHI_MIPI_CNTL2_CH_EN GENMASK(15, 11)
39 #define HHI_MIPI_CNTL2_CH0_LP_CTL GENMASK(10, 1)
41 #define DSI_LANE_0 BIT(4)
42 #define DSI_LANE_1 BIT(3)
43 #define DSI_LANE_CLK BIT(2)
44 #define DSI_LANE_2 BIT(1)
45 #define DSI_LANE_3 BIT(0)
47 struct phy_axg_mipi_pcie_analog_priv
{
49 struct regmap
*regmap
;
53 struct phy_configure_opts_mipi_dphy config
;
56 static void phy_bandgap_enable(struct phy_axg_mipi_pcie_analog_priv
*priv
)
58 regmap_update_bits(priv
->regmap
, HHI_MIPI_CNTL0
,
59 HHI_MIPI_CNTL0_BANDGAP
, HHI_MIPI_CNTL0_BANDGAP
);
61 regmap_update_bits(priv
->regmap
, HHI_MIPI_CNTL0
,
62 HHI_MIPI_CNTL0_ENABLE
, HHI_MIPI_CNTL0_ENABLE
);
65 static void phy_bandgap_disable(struct phy_axg_mipi_pcie_analog_priv
*priv
)
67 regmap_update_bits(priv
->regmap
, HHI_MIPI_CNTL0
,
68 HHI_MIPI_CNTL0_BANDGAP
, 0);
69 regmap_update_bits(priv
->regmap
, HHI_MIPI_CNTL0
,
70 HHI_MIPI_CNTL0_ENABLE
, 0);
73 static void phy_dsi_analog_enable(struct phy_axg_mipi_pcie_analog_priv
*priv
)
77 regmap_update_bits(priv
->regmap
, HHI_MIPI_CNTL0
,
78 HHI_MIPI_CNTL0_DIF_REF_CTL1
,
79 FIELD_PREP(HHI_MIPI_CNTL0_DIF_REF_CTL1
, 0x1b8));
80 regmap_update_bits(priv
->regmap
, HHI_MIPI_CNTL0
,
82 regmap_update_bits(priv
->regmap
, HHI_MIPI_CNTL0
,
83 HHI_MIPI_CNTL0_DIF_REF_CTL0
,
84 FIELD_PREP(HHI_MIPI_CNTL0_DIF_REF_CTL0
, 0x8));
86 regmap_write(priv
->regmap
, HHI_MIPI_CNTL1
, 0x001e);
88 regmap_write(priv
->regmap
, HHI_MIPI_CNTL2
,
89 (0x26e0 << 16) | (0x459 << 0));
92 switch (priv
->config
.lanes
) {
109 regmap_update_bits(priv
->regmap
, HHI_MIPI_CNTL2
,
110 HHI_MIPI_CNTL2_CH_EN
,
111 FIELD_PREP(HHI_MIPI_CNTL2_CH_EN
, reg
));
113 priv
->dsi_enabled
= true;
116 static void phy_dsi_analog_disable(struct phy_axg_mipi_pcie_analog_priv
*priv
)
118 regmap_update_bits(priv
->regmap
, HHI_MIPI_CNTL0
,
119 HHI_MIPI_CNTL0_DIF_REF_CTL1
,
120 FIELD_PREP(HHI_MIPI_CNTL0_DIF_REF_CTL1
, 0));
121 regmap_update_bits(priv
->regmap
, HHI_MIPI_CNTL0
, BIT(31), 0);
122 regmap_update_bits(priv
->regmap
, HHI_MIPI_CNTL0
,
123 HHI_MIPI_CNTL0_DIF_REF_CTL1
, 0);
125 regmap_write(priv
->regmap
, HHI_MIPI_CNTL1
, 0x6);
127 regmap_write(priv
->regmap
, HHI_MIPI_CNTL2
, 0x00200000);
129 priv
->dsi_enabled
= false;
132 static int phy_axg_mipi_pcie_analog_configure(struct phy
*phy
,
133 union phy_configure_opts
*opts
)
135 struct phy_axg_mipi_pcie_analog_priv
*priv
= phy_get_drvdata(phy
);
138 ret
= phy_mipi_dphy_config_validate(&opts
->mipi_dphy
);
142 memcpy(&priv
->config
, opts
, sizeof(priv
->config
));
144 priv
->dsi_configured
= true;
146 /* If PHY was already powered on, setup the DSI analog part */
148 /* If reconfiguring, disable & reconfigure */
149 if (priv
->dsi_enabled
)
150 phy_dsi_analog_disable(priv
);
152 usleep_range(100, 200);
154 phy_dsi_analog_enable(priv
);
160 static int phy_axg_mipi_pcie_analog_power_on(struct phy
*phy
)
162 struct phy_axg_mipi_pcie_analog_priv
*priv
= phy_get_drvdata(phy
);
164 phy_bandgap_enable(priv
);
166 if (priv
->dsi_configured
)
167 phy_dsi_analog_enable(priv
);
169 priv
->powered
= true;
174 static int phy_axg_mipi_pcie_analog_power_off(struct phy
*phy
)
176 struct phy_axg_mipi_pcie_analog_priv
*priv
= phy_get_drvdata(phy
);
178 phy_bandgap_disable(priv
);
180 if (priv
->dsi_enabled
)
181 phy_dsi_analog_disable(priv
);
183 priv
->powered
= false;
188 static const struct phy_ops phy_axg_mipi_pcie_analog_ops
= {
189 .configure
= phy_axg_mipi_pcie_analog_configure
,
190 .power_on
= phy_axg_mipi_pcie_analog_power_on
,
191 .power_off
= phy_axg_mipi_pcie_analog_power_off
,
192 .owner
= THIS_MODULE
,
195 static int phy_axg_mipi_pcie_analog_probe(struct platform_device
*pdev
)
197 struct phy_provider
*phy
;
198 struct device
*dev
= &pdev
->dev
;
199 struct phy_axg_mipi_pcie_analog_priv
*priv
;
200 struct device_node
*np
= dev
->of_node
;
204 priv
= devm_kmalloc(dev
, sizeof(*priv
), GFP_KERNEL
);
208 /* Get the hhi system controller node */
209 map
= syscon_node_to_regmap(of_get_parent(dev
->of_node
));
212 "failed to get HHI regmap\n");
218 priv
->phy
= devm_phy_create(dev
, np
, &phy_axg_mipi_pcie_analog_ops
);
219 if (IS_ERR(priv
->phy
)) {
220 ret
= PTR_ERR(priv
->phy
);
221 if (ret
!= -EPROBE_DEFER
)
222 dev_err(dev
, "failed to create PHY\n");
226 phy_set_drvdata(priv
->phy
, priv
);
227 dev_set_drvdata(dev
, priv
);
229 phy
= devm_of_phy_provider_register(dev
, of_phy_simple_xlate
);
231 return PTR_ERR_OR_ZERO(phy
);
234 static const struct of_device_id phy_axg_mipi_pcie_analog_of_match
[] = {
236 .compatible
= "amlogic,axg-mipi-pcie-analog-phy",
240 MODULE_DEVICE_TABLE(of
, phy_axg_mipi_pcie_analog_of_match
);
242 static struct platform_driver phy_axg_mipi_pcie_analog_driver
= {
243 .probe
= phy_axg_mipi_pcie_analog_probe
,
245 .name
= "phy-axg-mipi-pcie-analog",
246 .of_match_table
= phy_axg_mipi_pcie_analog_of_match
,
249 module_platform_driver(phy_axg_mipi_pcie_analog_driver
);
251 MODULE_AUTHOR("Remi Pommarel <repk@triplefau.lt>");
252 MODULE_DESCRIPTION("Amlogic AXG MIPI + PCIE analog PHY driver");
253 MODULE_LICENSE("GPL v2");