phy: rockchip-dp: Add support for rk3368 Display Port PHY
authorWeiYong Bi <bivvy.bi@rock-chips.com>
Sat, 25 Mar 2017 03:13:55 +0000 (11:13 +0800)
committerHuang, Tao <huangtao@rock-chips.com>
Mon, 27 Mar 2017 09:40:39 +0000 (17:40 +0800)
Change-Id: Ic2134ba719dadba121dc2fcc944662ef06b2ecfa
Signed-off-by: WeiYong Bi <bivvy.bi@rock-chips.com>
Documentation/devicetree/bindings/phy/rockchip-dp-phy.txt
drivers/phy/phy-rockchip-dp.c

index e3b4809fbe82c4798b7e5bef55e666505d6df527..b837bb8283297f82affc36981a4b69ca6a0eb81a 100644 (file)
@@ -4,14 +4,21 @@ Rockchip specific extensions to the Analogix Display Port PHY
 Required properties:
 - compatible : should be one of the following supported values:
         - "rockchip.rk3288-dp-phy"
+        - "rockchip.rk3368-dp-phy"
 - clocks: from common clock binding: handle to dp clock.
        of memory mapped region.
 - clock-names: from common clock binding:
        Required elements: "24m"
 - #phy-cells : from the generic PHY bindings, must be 0;
 
+Optional properties
+ - resets : phandle to the reset of eDP 24m clock domain.
+ - reset-names : should be "edp_24m".
+
 Example:
 
+For Rockchip RK3288:
+
 grf: syscon@ff770000 {
        compatible = "rockchip,rk3288-grf", "syscon", "simple-mfd";
 
@@ -24,3 +31,20 @@ grf: syscon@ff770000 {
                #phy-cells = <0>;
        };
 };
+
+For Rockchip RK3368:
+
+grf: syscon@ff770000 {
+       compatible = "rockchip,rk3368-grf", "syscon", "simple-mfd";
+
+...
+
+       edp_phy: edp-phy {
+               compatible = "rockchip,rk3368-dp-phy";
+               clocks = <&cru SCLK_EDP_24M>;
+               clock-names = "24m";
+               resets = <&cru SRST_EDP_24M>;
+               reset-names = "edp_24m";
+               #phy-cells = <0>;
+       };
+};
index 793ecb6d87bcaa2a56a914b2745bea6453929637..79576e99ab3e421f5408eb5246646c72989084f1 100644 (file)
  */
 
 #include <linux/clk.h>
+#include <linux/delay.h>
 #include <linux/mfd/syscon.h>
 #include <linux/module.h>
 #include <linux/of.h>
+#include <linux/of_device.h>
 #include <linux/phy/phy.h>
 #include <linux/platform_device.h>
 #include <linux/regmap.h>
+#include <linux/reset.h>
 
-#define GRF_SOC_CON12                           0x0274
-
-#define GRF_EDP_REF_CLK_SEL_INTER_HIWORD_MASK   BIT(20)
-#define GRF_EDP_REF_CLK_SEL_INTER               BIT(4)
-
-#define GRF_EDP_PHY_SIDDQ_HIWORD_MASK           BIT(21)
-#define GRF_EDP_PHY_SIDDQ_ON                    0
-#define GRF_EDP_PHY_SIDDQ_OFF                   BIT(5)
+struct rockchip_dp_phy_drv_data {
+       u32 grf_reg_offset;
+       u32 ref_clk_sel_inter;
+       u32 siddq_on;
+       u32 siddq_off;
+};
 
 struct rockchip_dp_phy {
        struct device  *dev;
        struct regmap  *grf;
        struct clk     *phy_24m;
+       struct reset_control *rst_24m;
+
+       const struct rockchip_dp_phy_drv_data *drv_data;
 };
 
 static int rockchip_set_phy_state(struct phy *phy, bool enable)
 {
        struct rockchip_dp_phy *dp = phy_get_drvdata(phy);
+       const struct rockchip_dp_phy_drv_data *drv_data = dp->drv_data;
        int ret;
 
        if (enable) {
-               ret = regmap_write(dp->grf, GRF_SOC_CON12,
-                                  GRF_EDP_PHY_SIDDQ_HIWORD_MASK |
-                                  GRF_EDP_PHY_SIDDQ_ON);
+               /* EDP 24m clock domain software reset request. */
+               reset_control_assert(dp->rst_24m);
+               usleep_range(20, 40);
+               reset_control_deassert(dp->rst_24m);
+               usleep_range(20, 40);
+
+               ret = regmap_write(dp->grf, drv_data->grf_reg_offset,
+                                  drv_data->siddq_on);
                if (ret < 0) {
                        dev_err(dp->dev, "Can't enable PHY power %d\n", ret);
                        return ret;
@@ -50,9 +60,8 @@ static int rockchip_set_phy_state(struct phy *phy, bool enable)
        } else {
                clk_disable_unprepare(dp->phy_24m);
 
-               ret = regmap_write(dp->grf, GRF_SOC_CON12,
-                                  GRF_EDP_PHY_SIDDQ_HIWORD_MASK |
-                                  GRF_EDP_PHY_SIDDQ_OFF);
+               ret = regmap_write(dp->grf, drv_data->grf_reg_offset,
+                                  drv_data->siddq_off);
        }
 
        return ret;
@@ -80,6 +89,7 @@ static int rockchip_dp_phy_probe(struct platform_device *pdev)
        struct device_node *np = dev->of_node;
        struct phy_provider *phy_provider;
        struct rockchip_dp_phy *dp;
+       const struct rockchip_dp_phy_drv_data *drv_data;
        struct phy *phy;
        int ret;
 
@@ -89,11 +99,18 @@ static int rockchip_dp_phy_probe(struct platform_device *pdev)
        if (!dev->parent || !dev->parent->of_node)
                return -ENODEV;
 
+       drv_data = of_device_get_match_data(dev);
+       if (!drv_data) {
+               dev_err(dev, "No OF match data provided\n");
+               return -EINVAL;
+       }
+
        dp = devm_kzalloc(dev, sizeof(*dp), GFP_KERNEL);
        if (IS_ERR(dp))
                return -ENOMEM;
 
        dp->dev = dev;
+       dp->drv_data = drv_data;
 
        dp->phy_24m = devm_clk_get(dev, "24m");
        if (IS_ERR(dp->phy_24m)) {
@@ -107,15 +124,22 @@ static int rockchip_dp_phy_probe(struct platform_device *pdev)
                return ret;
        }
 
+       /* optional */
+       dp->rst_24m = devm_reset_control_get_optional(&pdev->dev, "edp_24m");
+       if (IS_ERR(dp->rst_24m)) {
+               dev_info(dev, "No edp_24m reset control specified\n");
+               dp->rst_24m = NULL;
+       }
+
        dp->grf = syscon_node_to_regmap(dev->parent->of_node);
        if (IS_ERR(dp->grf)) {
                dev_err(dev, "rk3288-dp needs the General Register Files syscon\n");
                return PTR_ERR(dp->grf);
        }
 
-       ret = regmap_write(dp->grf, GRF_SOC_CON12, GRF_EDP_REF_CLK_SEL_INTER |
-                          GRF_EDP_REF_CLK_SEL_INTER_HIWORD_MASK);
-       if (ret != 0) {
+       ret = regmap_write(dp->grf, drv_data->grf_reg_offset,
+                          drv_data->ref_clk_sel_inter);
+       if (ret) {
                dev_err(dp->dev, "Could not config GRF edp ref clk: %d\n", ret);
                return ret;
        }
@@ -132,8 +156,25 @@ static int rockchip_dp_phy_probe(struct platform_device *pdev)
        return PTR_ERR_OR_ZERO(phy_provider);
 }
 
+static const struct rockchip_dp_phy_drv_data rk3288_dp_phy_drv_data = {
+       .grf_reg_offset = 0x274,
+       .ref_clk_sel_inter = BIT(4) | BIT(20),
+       .siddq_on = 0 | BIT(21),
+       .siddq_off = BIT(5) | BIT(21),
+};
+
+static const struct rockchip_dp_phy_drv_data rk3368_dp_phy_drv_data = {
+       .grf_reg_offset = 0x410,
+       .ref_clk_sel_inter = BIT(0) | BIT(16),
+       .siddq_on = 0 | BIT(17),
+       .siddq_off = BIT(1) | BIT(17),
+};
+
 static const struct of_device_id rockchip_dp_phy_dt_ids[] = {
-       { .compatible = "rockchip,rk3288-dp-phy" },
+       { .compatible = "rockchip,rk3288-dp-phy",
+         .data = &rk3288_dp_phy_drv_data },
+       { .compatible = "rockchip,rk3368-dp-phy",
+         .data = &rk3368_dp_phy_drv_data },
        {}
 };