soc: rockchip: amend rk3368-mbox related *.h to soc/rockchip
[firefly-linux-kernel-4.4.55.git] / drivers / phy / phy-rockchip-dp.c
1 /*
2  * Rockchip DP PHY driver
3  *
4  * Copyright (C) 2016 FuZhou Rockchip Co., Ltd.
5  * Author: Yakir Yang <ykk@@rock-chips.com>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License.
10  */
11
12 #include <linux/clk.h>
13 #include <linux/delay.h>
14 #include <linux/mfd/syscon.h>
15 #include <linux/module.h>
16 #include <linux/of.h>
17 #include <linux/of_device.h>
18 #include <linux/phy/phy.h>
19 #include <linux/platform_device.h>
20 #include <linux/regmap.h>
21 #include <linux/reset.h>
22
23 struct rockchip_dp_phy_drv_data {
24         u32 grf_reg_offset;
25         u32 ref_clk_sel_inter;
26         u32 siddq_on;
27         u32 siddq_off;
28 };
29
30 struct rockchip_dp_phy {
31         struct device  *dev;
32         struct regmap  *grf;
33         struct clk     *phy_24m;
34         struct reset_control *rst_24m;
35
36         const struct rockchip_dp_phy_drv_data *drv_data;
37 };
38
39 static int rockchip_set_phy_state(struct phy *phy, bool enable)
40 {
41         struct rockchip_dp_phy *dp = phy_get_drvdata(phy);
42         const struct rockchip_dp_phy_drv_data *drv_data = dp->drv_data;
43         int ret;
44
45         if (enable) {
46                 if (dp->rst_24m) {
47                         /* EDP 24m clock domain software reset request. */
48                         reset_control_assert(dp->rst_24m);
49                         usleep_range(20, 40);
50                         reset_control_deassert(dp->rst_24m);
51                         usleep_range(20, 40);
52                 }
53
54                 ret = regmap_write(dp->grf, drv_data->grf_reg_offset,
55                                    drv_data->siddq_on);
56                 if (ret < 0) {
57                         dev_err(dp->dev, "Can't enable PHY power %d\n", ret);
58                         return ret;
59                 }
60
61                 ret = clk_prepare_enable(dp->phy_24m);
62         } else {
63                 clk_disable_unprepare(dp->phy_24m);
64
65                 ret = regmap_write(dp->grf, drv_data->grf_reg_offset,
66                                    drv_data->siddq_off);
67         }
68
69         return ret;
70 }
71
72 static int rockchip_dp_phy_power_on(struct phy *phy)
73 {
74         return rockchip_set_phy_state(phy, true);
75 }
76
77 static int rockchip_dp_phy_power_off(struct phy *phy)
78 {
79         return rockchip_set_phy_state(phy, false);
80 }
81
82 static const struct phy_ops rockchip_dp_phy_ops = {
83         .power_on       = rockchip_dp_phy_power_on,
84         .power_off      = rockchip_dp_phy_power_off,
85         .owner          = THIS_MODULE,
86 };
87
88 static int rockchip_dp_phy_probe(struct platform_device *pdev)
89 {
90         struct device *dev = &pdev->dev;
91         struct device_node *np = dev->of_node;
92         struct phy_provider *phy_provider;
93         struct rockchip_dp_phy *dp;
94         const struct rockchip_dp_phy_drv_data *drv_data;
95         struct phy *phy;
96         int ret;
97
98         if (!np)
99                 return -ENODEV;
100
101         if (!dev->parent || !dev->parent->of_node)
102                 return -ENODEV;
103
104         drv_data = of_device_get_match_data(dev);
105         if (!drv_data) {
106                 dev_err(dev, "No OF match data provided\n");
107                 return -EINVAL;
108         }
109
110         dp = devm_kzalloc(dev, sizeof(*dp), GFP_KERNEL);
111         if (IS_ERR(dp))
112                 return -ENOMEM;
113
114         dp->dev = dev;
115         dp->drv_data = drv_data;
116
117         dp->phy_24m = devm_clk_get(dev, "24m");
118         if (IS_ERR(dp->phy_24m)) {
119                 dev_err(dev, "cannot get clock 24m\n");
120                 return PTR_ERR(dp->phy_24m);
121         }
122
123         ret = clk_set_rate(dp->phy_24m, 24000000);
124         if (ret < 0) {
125                 dev_err(dp->dev, "cannot set clock phy_24m %d\n", ret);
126                 return ret;
127         }
128
129         /* optional */
130         dp->rst_24m = devm_reset_control_get_optional(&pdev->dev, "edp_24m");
131         if (IS_ERR(dp->rst_24m)) {
132                 dev_info(dev, "No edp_24m reset control specified\n");
133                 dp->rst_24m = NULL;
134         }
135
136         dp->grf = syscon_node_to_regmap(dev->parent->of_node);
137         if (IS_ERR(dp->grf)) {
138                 dev_err(dev, "rk3288-dp needs the General Register Files syscon\n");
139                 return PTR_ERR(dp->grf);
140         }
141
142         ret = regmap_write(dp->grf, drv_data->grf_reg_offset,
143                            drv_data->ref_clk_sel_inter);
144         if (ret) {
145                 dev_err(dp->dev, "Could not config GRF edp ref clk: %d\n", ret);
146                 return ret;
147         }
148
149         phy = devm_phy_create(dev, np, &rockchip_dp_phy_ops);
150         if (IS_ERR(phy)) {
151                 dev_err(dev, "failed to create phy\n");
152                 return PTR_ERR(phy);
153         }
154         phy_set_drvdata(phy, dp);
155
156         phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
157
158         return PTR_ERR_OR_ZERO(phy_provider);
159 }
160
161 static const struct rockchip_dp_phy_drv_data rk3288_dp_phy_drv_data = {
162         .grf_reg_offset = 0x274,
163         .ref_clk_sel_inter = BIT(4) | BIT(20),
164         .siddq_on = 0 | BIT(21),
165         .siddq_off = BIT(5) | BIT(21),
166 };
167
168 static const struct rockchip_dp_phy_drv_data rk3368_dp_phy_drv_data = {
169         .grf_reg_offset = 0x410,
170         .ref_clk_sel_inter = BIT(0) | BIT(16),
171         .siddq_on = 0 | BIT(17),
172         .siddq_off = BIT(1) | BIT(17),
173 };
174
175 static const struct of_device_id rockchip_dp_phy_dt_ids[] = {
176         { .compatible = "rockchip,rk3288-dp-phy",
177           .data = &rk3288_dp_phy_drv_data },
178         { .compatible = "rockchip,rk3368-dp-phy",
179           .data = &rk3368_dp_phy_drv_data },
180         {}
181 };
182
183 MODULE_DEVICE_TABLE(of, rockchip_dp_phy_dt_ids);
184
185 static struct platform_driver rockchip_dp_phy_driver = {
186         .probe          = rockchip_dp_phy_probe,
187         .driver         = {
188                 .name   = "rockchip-dp-phy",
189                 .of_match_table = rockchip_dp_phy_dt_ids,
190         },
191 };
192
193 module_platform_driver(rockchip_dp_phy_driver);
194
195 MODULE_AUTHOR("Yakir Yang <ykk@rock-chips.com>");
196 MODULE_DESCRIPTION("Rockchip DP PHY driver");
197 MODULE_LICENSE("GPL v2");