Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

phy: Add driver for rockchip Display Port PHY

Add phy driver for the Rockchip DisplayPort PHY module. This
is required to get DisplayPort working in Rockchip SoCs.

Signed-off-by: Yakir Yang <ykk@rock-chips.com>
Reviewed-by: Heiko Stuebner <heiko@sntech.de>
Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>

authored by

Yakir Yang and committed by
Kishon Vijay Abraham I
fd968973 c474a949

+159
+7
drivers/phy/Kconfig
··· 344 344 help 345 345 Enable this to support the Rockchip EMMC PHY. 346 346 347 + config PHY_ROCKCHIP_DP 348 + tristate "Rockchip Display Port PHY Driver" 349 + depends on ARCH_ROCKCHIP && OF 350 + select GENERIC_PHY 351 + help 352 + Enable this to support the Rockchip Display Port PHY. 353 + 347 354 config PHY_ST_SPEAR1310_MIPHY 348 355 tristate "ST SPEAR1310-MIPHY driver" 349 356 select GENERIC_PHY
+1
drivers/phy/Makefile
··· 38 38 obj-$(CONFIG_PHY_QCOM_APQ8064_SATA) += phy-qcom-apq8064-sata.o 39 39 obj-$(CONFIG_PHY_ROCKCHIP_USB) += phy-rockchip-usb.o 40 40 obj-$(CONFIG_PHY_ROCKCHIP_EMMC) += phy-rockchip-emmc.o 41 + obj-$(CONFIG_PHY_ROCKCHIP_DP) += phy-rockchip-dp.o 41 42 obj-$(CONFIG_PHY_QCOM_IPQ806X_SATA) += phy-qcom-ipq806x-sata.o 42 43 obj-$(CONFIG_PHY_ST_SPEAR1310_MIPHY) += phy-spear1310-miphy.o 43 44 obj-$(CONFIG_PHY_ST_SPEAR1340_MIPHY) += phy-spear1340-miphy.o
+151
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/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 + dp = devm_kzalloc(dev, sizeof(*dp), GFP_KERNEL); 90 + if (IS_ERR(dp)) 91 + return -ENOMEM; 92 + 93 + dp->dev = dev; 94 + 95 + dp->phy_24m = devm_clk_get(dev, "24m"); 96 + if (IS_ERR(dp->phy_24m)) { 97 + dev_err(dev, "cannot get clock 24m\n"); 98 + return PTR_ERR(dp->phy_24m); 99 + } 100 + 101 + ret = clk_set_rate(dp->phy_24m, 24000000); 102 + if (ret < 0) { 103 + dev_err(dp->dev, "cannot set clock phy_24m %d\n", ret); 104 + return ret; 105 + } 106 + 107 + dp->grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf"); 108 + if (IS_ERR(dp->grf)) { 109 + dev_err(dev, "rk3288-dp needs rockchip,grf property\n"); 110 + return PTR_ERR(dp->grf); 111 + } 112 + 113 + ret = regmap_write(dp->grf, GRF_SOC_CON12, GRF_EDP_REF_CLK_SEL_INTER | 114 + GRF_EDP_REF_CLK_SEL_INTER_HIWORD_MASK); 115 + if (ret != 0) { 116 + dev_err(dp->dev, "Could not config GRF edp ref clk: %d\n", ret); 117 + return ret; 118 + } 119 + 120 + phy = devm_phy_create(dev, np, &rockchip_dp_phy_ops); 121 + if (IS_ERR(phy)) { 122 + dev_err(dev, "failed to create phy\n"); 123 + return PTR_ERR(phy); 124 + } 125 + phy_set_drvdata(phy, dp); 126 + 127 + phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); 128 + 129 + return PTR_ERR_OR_ZERO(phy_provider); 130 + } 131 + 132 + static const struct of_device_id rockchip_dp_phy_dt_ids[] = { 133 + { .compatible = "rockchip,rk3288-dp-phy" }, 134 + {} 135 + }; 136 + 137 + MODULE_DEVICE_TABLE(of, rockchip_dp_phy_dt_ids); 138 + 139 + static struct platform_driver rockchip_dp_phy_driver = { 140 + .probe = rockchip_dp_phy_probe, 141 + .driver = { 142 + .name = "rockchip-dp-phy", 143 + .of_match_table = rockchip_dp_phy_dt_ids, 144 + }, 145 + }; 146 + 147 + module_platform_driver(rockchip_dp_phy_driver); 148 + 149 + MODULE_AUTHOR("Yakir Yang <ykk@rock-chips.com>"); 150 + MODULE_DESCRIPTION("Rockchip DP PHY driver"); 151 + MODULE_LICENSE("GPL v2");