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