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

mmc: sdhci-of-arasan: Add support to set clock phase delays for SD

Add support to read Clock Phase Delays from the DT and set it via
clk_set_phase() API from clock framework. Some of the controllers might
have their own handling of setting clock delays, for this keep the
set_clk_delays as function pointer which can be assigned controller
specific handling of the same.

Signed-off-by: Manish Narani <manish.narani@xilinx.com>
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>

authored by

Manish Narani and committed by
Ulf Hansson
f3dafc37 fec81c5b

+92
+92
drivers/mmc/host/sdhci-of-arasan.c
··· 77 77 * @sdcardclk: Pointer to normal 'struct clock' for sdcardclk_hw. 78 78 * @sampleclk_hw: Struct for the clock we might provide to a PHY. 79 79 * @sampleclk: Pointer to normal 'struct clock' for sampleclk_hw. 80 + * @clk_phase_in: Array of Input Clock Phase Delays for all speed modes 81 + * @clk_phase_out: Array of Output Clock Phase Delays for all speed modes 82 + * @set_clk_delays: Function pointer for setting Clock Delays 80 83 */ 81 84 struct sdhci_arasan_clk_data { 82 85 struct clk_hw sdcardclk_hw; 83 86 struct clk *sdcardclk; 84 87 struct clk_hw sampleclk_hw; 85 88 struct clk *sampleclk; 89 + int clk_phase_in[MMC_TIMING_MMC_HS400 + 1]; 90 + int clk_phase_out[MMC_TIMING_MMC_HS400 + 1]; 91 + void (*set_clk_delays)(struct sdhci_host *host); 86 92 }; 87 93 88 94 /** ··· 198 192 { 199 193 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 200 194 struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host); 195 + struct sdhci_arasan_clk_data *clk_data = &sdhci_arasan->clk_data; 201 196 bool ctrl_phy = false; 202 197 203 198 if (!IS_ERR(sdhci_arasan->phy)) { ··· 239 232 phy_power_off(sdhci_arasan->phy); 240 233 sdhci_arasan->is_phy_on = false; 241 234 } 235 + 236 + /* Set the Input and Output Clock Phase Delays */ 237 + if (clk_data->set_clk_delays) 238 + clk_data->set_clk_delays(host); 242 239 243 240 sdhci_set_clock(host, clock); 244 241 ··· 676 665 sdhci_arasan_syscon_write(host, &soc_ctl_map->baseclkfreq, mhz); 677 666 } 678 667 668 + static void sdhci_arasan_set_clk_delays(struct sdhci_host *host) 669 + { 670 + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 671 + struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host); 672 + struct sdhci_arasan_clk_data *clk_data = &sdhci_arasan->clk_data; 673 + 674 + clk_set_phase(clk_data->sampleclk, 675 + clk_data->clk_phase_in[host->timing]); 676 + clk_set_phase(clk_data->sdcardclk, 677 + clk_data->clk_phase_out[host->timing]); 678 + } 679 + 680 + static void arasan_dt_read_clk_phase(struct device *dev, 681 + struct sdhci_arasan_clk_data *clk_data, 682 + unsigned int timing, const char *prop) 683 + { 684 + struct device_node *np = dev->of_node; 685 + 686 + int clk_phase[2] = {0}; 687 + 688 + /* 689 + * Read Tap Delay values from DT, if the DT does not contain the 690 + * Tap Values then use the pre-defined values. 691 + */ 692 + if (of_property_read_variable_u32_array(np, prop, &clk_phase[0], 693 + 2, 0)) { 694 + dev_dbg(dev, "Using predefined clock phase for %s = %d %d\n", 695 + prop, clk_data->clk_phase_in[timing], 696 + clk_data->clk_phase_out[timing]); 697 + return; 698 + } 699 + 700 + /* The values read are Input and Output Clock Delays in order */ 701 + clk_data->clk_phase_in[timing] = clk_phase[0]; 702 + clk_data->clk_phase_out[timing] = clk_phase[1]; 703 + } 704 + 705 + /** 706 + * arasan_dt_parse_clk_phases - Read Clock Delay values from DT 707 + * 708 + * Called at initialization to parse the values of Clock Delays. 709 + * 710 + * @dev: Pointer to our struct device. 711 + * @clk_data: Pointer to the Clock Data structure 712 + */ 713 + static void arasan_dt_parse_clk_phases(struct device *dev, 714 + struct sdhci_arasan_clk_data *clk_data) 715 + { 716 + /* 717 + * This has been kept as a pointer and is assigned a function here. 718 + * So that different controller variants can assign their own handling 719 + * function. 720 + */ 721 + clk_data->set_clk_delays = sdhci_arasan_set_clk_delays; 722 + 723 + arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_LEGACY, 724 + "clk-phase-legacy"); 725 + arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_MMC_HS, 726 + "clk-phase-mmc-hs"); 727 + arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_SD_HS, 728 + "clk-phase-sd-hs"); 729 + arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_UHS_SDR12, 730 + "clk-phase-uhs-sdr12"); 731 + arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_UHS_SDR25, 732 + "clk-phase-uhs-sdr25"); 733 + arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_UHS_SDR50, 734 + "clk-phase-uhs-sdr50"); 735 + arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_UHS_SDR104, 736 + "clk-phase-uhs-sdr104"); 737 + arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_UHS_DDR50, 738 + "clk-phase-uhs-ddr50"); 739 + arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_MMC_DDR52, 740 + "clk-phase-mmc-ddr52"); 741 + arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_MMC_HS200, 742 + "clk-phase-mmc-hs200"); 743 + arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_MMC_HS400, 744 + "clk-phase-mmc-hs400"); 745 + } 746 + 679 747 /** 680 748 * sdhci_arasan_register_sdcardclk - Register the sdcardclk for a PHY to use 681 749 * ··· 1046 956 ret = sdhci_arasan_register_sdclk(sdhci_arasan, clk_xin, &pdev->dev); 1047 957 if (ret) 1048 958 goto clk_disable_all; 959 + 960 + arasan_dt_parse_clk_phases(&pdev->dev, &sdhci_arasan->clk_data); 1049 961 1050 962 ret = mmc_of_parse(host->mmc); 1051 963 if (ret) {