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/mfd/syscon.h> 14 #include <linux/module.h> 15 #include <linux/of.h> 16 #include <linux/phy/phy.h> 17 #include <linux/platform_device.h> 18 #include <linux/regmap.h> 19 20 #define GRF_SOC_CON12 0x0274 21 22 #define GRF_EDP_REF_CLK_SEL_INTER_HIWORD_MASK BIT(20) 23 #define GRF_EDP_REF_CLK_SEL_INTER BIT(4) 24 25 #define GRF_EDP_PHY_SIDDQ_HIWORD_MASK BIT(21) 26 #define GRF_EDP_PHY_SIDDQ_ON 0 27 #define GRF_EDP_PHY_SIDDQ_OFF BIT(5) 28 29 struct rockchip_dp_phy { 30 struct device *dev; 31 struct regmap *grf; 32 struct clk *phy_24m; 33 }; 34 35 static int rockchip_set_phy_state(struct phy *phy, bool enable) 36 { 37 struct rockchip_dp_phy *dp = phy_get_drvdata(phy); 38 int ret; 39 40 if (enable) { 41 ret = regmap_write(dp->grf, GRF_SOC_CON12, 42 GRF_EDP_PHY_SIDDQ_HIWORD_MASK | 43 GRF_EDP_PHY_SIDDQ_ON); 44 if (ret < 0) { 45 dev_err(dp->dev, "Can't enable PHY power %d\n", ret); 46 return ret; 47 } 48 49 ret = clk_prepare_enable(dp->phy_24m); 50 } else { 51 clk_disable_unprepare(dp->phy_24m); 52 53 ret = regmap_write(dp->grf, GRF_SOC_CON12, 54 GRF_EDP_PHY_SIDDQ_HIWORD_MASK | 55 GRF_EDP_PHY_SIDDQ_OFF); 56 } 57 58 return ret; 59 } 60 61 static int rockchip_dp_phy_power_on(struct phy *phy) 62 { 63 return rockchip_set_phy_state(phy, true); 64 } 65 66 static int rockchip_dp_phy_power_off(struct phy *phy) 67 { 68 return rockchip_set_phy_state(phy, false); 69 } 70 71 static const struct phy_ops rockchip_dp_phy_ops = { 72 .power_on = rockchip_dp_phy_power_on, 73 .power_off = rockchip_dp_phy_power_off, 74 .owner = THIS_MODULE, 75 }; 76 77 static int rockchip_dp_phy_probe(struct platform_device *pdev) 78 { 79 struct device *dev = &pdev->dev; 80 struct device_node *np = dev->of_node; 81 struct phy_provider *phy_provider; 82 struct rockchip_dp_phy *dp; 83 struct phy *phy; 84 int ret; 85 86 if (!np) 87 return -ENODEV; 88 89 if (!dev->parent || !dev->parent->of_node) 90 return -ENODEV; 91 92 dp = devm_kzalloc(dev, sizeof(*dp), GFP_KERNEL); 93 if (!dp) 94 return -ENOMEM; 95 96 dp->dev = dev; 97 98 dp->phy_24m = devm_clk_get(dev, "24m"); 99 if (IS_ERR(dp->phy_24m)) { 100 dev_err(dev, "cannot get clock 24m\n"); 101 return PTR_ERR(dp->phy_24m); 102 } 103 104 ret = clk_set_rate(dp->phy_24m, 24000000); 105 if (ret < 0) { 106 dev_err(dp->dev, "cannot set clock phy_24m %d\n", ret); 107 return ret; 108 } 109 110 dp->grf = syscon_node_to_regmap(dev->parent->of_node); 111 if (IS_ERR(dp->grf)) { 112 dev_err(dev, "rk3288-dp needs the General Register Files syscon\n"); 113 return PTR_ERR(dp->grf); 114 } 115 116 ret = regmap_write(dp->grf, GRF_SOC_CON12, GRF_EDP_REF_CLK_SEL_INTER | 117 GRF_EDP_REF_CLK_SEL_INTER_HIWORD_MASK); 118 if (ret != 0) { 119 dev_err(dp->dev, "Could not config GRF edp ref clk: %d\n", ret); 120 return ret; 121 } 122 123 phy = devm_phy_create(dev, np, &rockchip_dp_phy_ops); 124 if (IS_ERR(phy)) { 125 dev_err(dev, "failed to create phy\n"); 126 return PTR_ERR(phy); 127 } 128 phy_set_drvdata(phy, dp); 129 130 phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); 131 132 return PTR_ERR_OR_ZERO(phy_provider); 133 } 134 135 static const struct of_device_id rockchip_dp_phy_dt_ids[] = { 136 { .compatible = "rockchip,rk3288-dp-phy" }, 137 {} 138 }; 139 140 MODULE_DEVICE_TABLE(of, rockchip_dp_phy_dt_ids); 141 142 static struct platform_driver rockchip_dp_phy_driver = { 143 .probe = rockchip_dp_phy_probe, 144 .driver = { 145 .name = "rockchip-dp-phy", 146 .of_match_table = rockchip_dp_phy_dt_ids, 147 }, 148 }; 149 150 module_platform_driver(rockchip_dp_phy_driver); 151 152 MODULE_AUTHOR("Yakir Yang <ykk@rock-chips.com>"); 153 MODULE_DESCRIPTION("Rockchip DP PHY driver"); 154 MODULE_LICENSE("GPL v2"); 155