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

phy: zynqmp: Handle the clock enable/disable properly

The current driver is not handling the clock enable/disable operations
properly. The clocks need to be handled correctly by enabling or
disabling at appropriate places. This patch adds code to handle the
same.

Signed-off-by: Manish Narani <manish.narani@xilinx.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Acked-by: Michal Simek <michal.simek@xilinx.com>
Link: https://lore.kernel.org/r/1616588325-95602-1-git-send-email-manish.narani@xilinx.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>

authored by

Manish Narani and committed by
Vinod Koul
67097754 5e15fdc3

+51 -7
+51 -7
drivers/phy/xilinx/phy-zynqmp.c
··· 208 208 * @gtr_mutex: mutex for locking 209 209 * @phys: PHY lanes 210 210 * @refclk_sscs: spread spectrum settings for the reference clocks 211 + * @clk: reference clocks 211 212 * @tx_term_fix: fix for GT issue 212 213 * @saved_icm_cfg0: stored value of ICM CFG0 register 213 214 * @saved_icm_cfg1: stored value of ICM CFG1 register ··· 220 219 struct mutex gtr_mutex; /* mutex for locking */ 221 220 struct xpsgtr_phy phys[NUM_LANES]; 222 221 const struct xpsgtr_ssc *refclk_sscs[NUM_LANES]; 222 + struct clk *clk[NUM_LANES]; 223 223 bool tx_term_fix; 224 224 unsigned int saved_icm_cfg0; 225 225 unsigned int saved_icm_cfg1; ··· 820 818 static int __maybe_unused xpsgtr_suspend(struct device *dev) 821 819 { 822 820 struct xpsgtr_dev *gtr_dev = dev_get_drvdata(dev); 821 + unsigned int i; 823 822 824 823 /* Save the snapshot ICM_CFG registers. */ 825 824 gtr_dev->saved_icm_cfg0 = xpsgtr_read(gtr_dev, ICM_CFG0); 826 825 gtr_dev->saved_icm_cfg1 = xpsgtr_read(gtr_dev, ICM_CFG1); 826 + 827 + for (i = 0; i < ARRAY_SIZE(gtr_dev->clk); i++) 828 + clk_disable_unprepare(gtr_dev->clk[i]); 827 829 828 830 return 0; 829 831 } ··· 838 832 unsigned int icm_cfg0, icm_cfg1; 839 833 unsigned int i; 840 834 bool skip_phy_init; 835 + int err; 836 + 837 + for (i = 0; i < ARRAY_SIZE(gtr_dev->clk); i++) { 838 + err = clk_prepare_enable(gtr_dev->clk[i]); 839 + if (err) 840 + goto err_clk_put; 841 + } 841 842 842 843 icm_cfg0 = xpsgtr_read(gtr_dev, ICM_CFG0); 843 844 icm_cfg1 = xpsgtr_read(gtr_dev, ICM_CFG1); ··· 865 852 gtr_dev->phys[i].skip_phy_init = skip_phy_init; 866 853 867 854 return 0; 855 + 856 + err_clk_put: 857 + while (i--) 858 + clk_disable_unprepare(gtr_dev->clk[i]); 859 + 860 + return err; 868 861 } 869 862 870 863 static const struct dev_pm_ops xpsgtr_pm_ops = { ··· 884 865 static int xpsgtr_get_ref_clocks(struct xpsgtr_dev *gtr_dev) 885 866 { 886 867 unsigned int refclk; 868 + int ret; 887 869 888 870 for (refclk = 0; refclk < ARRAY_SIZE(gtr_dev->refclk_sscs); ++refclk) { 889 871 unsigned long rate; ··· 894 874 895 875 snprintf(name, sizeof(name), "ref%u", refclk); 896 876 clk = devm_clk_get_optional(gtr_dev->dev, name); 897 - if (IS_ERR(clk)) 898 - return dev_err_probe(gtr_dev->dev, PTR_ERR(clk), 899 - "Failed to get reference clock %u\n", 900 - refclk); 877 + if (IS_ERR(clk)) { 878 + ret = dev_err_probe(gtr_dev->dev, PTR_ERR(clk), 879 + "Failed to get reference clock %u\n", 880 + refclk); 881 + goto err_clk_put; 882 + } 901 883 902 884 if (!clk) 903 885 continue; 886 + 887 + ret = clk_prepare_enable(clk); 888 + if (ret) 889 + goto err_clk_put; 890 + 891 + gtr_dev->clk[refclk] = clk; 904 892 905 893 /* 906 894 * Get the spread spectrum (SSC) settings for the reference ··· 927 899 dev_err(gtr_dev->dev, 928 900 "Invalid rate %lu for reference clock %u\n", 929 901 rate, refclk); 930 - return -EINVAL; 902 + ret = -EINVAL; 903 + goto err_clk_put; 931 904 } 932 905 } 933 906 934 907 return 0; 908 + 909 + err_clk_put: 910 + while (refclk--) 911 + clk_disable_unprepare(gtr_dev->clk[refclk]); 912 + 913 + return ret; 935 914 } 936 915 937 916 static int xpsgtr_probe(struct platform_device *pdev) ··· 947 912 struct xpsgtr_dev *gtr_dev; 948 913 struct phy_provider *provider; 949 914 unsigned int port; 915 + unsigned int i; 950 916 int ret; 951 917 952 918 gtr_dev = devm_kzalloc(&pdev->dev, sizeof(*gtr_dev), GFP_KERNEL); ··· 987 951 phy = devm_phy_create(&pdev->dev, np, &xpsgtr_phyops); 988 952 if (IS_ERR(phy)) { 989 953 dev_err(&pdev->dev, "failed to create PHY\n"); 990 - return PTR_ERR(phy); 954 + ret = PTR_ERR(phy); 955 + goto err_clk_put; 991 956 } 992 957 993 958 gtr_phy->phy = phy; ··· 999 962 provider = devm_of_phy_provider_register(&pdev->dev, xpsgtr_xlate); 1000 963 if (IS_ERR(provider)) { 1001 964 dev_err(&pdev->dev, "registering provider failed\n"); 1002 - return PTR_ERR(provider); 965 + ret = PTR_ERR(provider); 966 + goto err_clk_put; 1003 967 } 1004 968 return 0; 969 + 970 + err_clk_put: 971 + for (i = 0; i < ARRAY_SIZE(gtr_dev->clk); i++) 972 + clk_disable_unprepare(gtr_dev->clk[i]); 973 + 974 + return ret; 1005 975 } 1006 976 1007 977 static const struct of_device_id xpsgtr_of_match[] = {