aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/mmc/host/sdhci-sirf.c71
1 files changed, 71 insertions, 0 deletions
diff --git a/drivers/mmc/host/sdhci-sirf.c b/drivers/mmc/host/sdhci-sirf.c
index dd29d47c07aa..5b956b37165f 100644
--- a/drivers/mmc/host/sdhci-sirf.c
+++ b/drivers/mmc/host/sdhci-sirf.c
@@ -15,7 +15,9 @@
15#include <linux/mmc/slot-gpio.h> 15#include <linux/mmc/slot-gpio.h>
16#include "sdhci-pltfm.h" 16#include "sdhci-pltfm.h"
17 17
18#define SDHCI_CLK_DELAY_SETTING 0x4C
18#define SDHCI_SIRF_8BITBUS BIT(3) 19#define SDHCI_SIRF_8BITBUS BIT(3)
20#define SIRF_TUNING_COUNT 128
19 21
20struct sdhci_sirf_priv { 22struct sdhci_sirf_priv {
21 struct clk *clk; 23 struct clk *clk;
@@ -49,7 +51,76 @@ static void sdhci_sirf_set_bus_width(struct sdhci_host *host, int width)
49 sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); 51 sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
50} 52}
51 53
54static int sdhci_sirf_execute_tuning(struct sdhci_host *host, u32 opcode)
55{
56 int tuning_seq_cnt = 3;
57 u8 phase, tuned_phases[SIRF_TUNING_COUNT];
58 u8 tuned_phase_cnt = 0;
59 int rc, longest_range = 0;
60 int start = -1, end = 0, tuning_value = -1, range = 0;
61 u16 clock_setting;
62 struct mmc_host *mmc = host->mmc;
63
64 clock_setting = sdhci_readw(host, SDHCI_CLK_DELAY_SETTING);
65 clock_setting &= ~0x3fff;
66
67retry:
68 phase = 0;
69 do {
70 sdhci_writel(host,
71 clock_setting | phase | (phase << 7) | (phase << 16),
72 SDHCI_CLK_DELAY_SETTING);
73
74 if (!mmc_send_tuning(mmc)) {
75 /* Tuning is successful at this tuning point */
76 tuned_phases[tuned_phase_cnt++] = phase;
77 dev_dbg(mmc_dev(mmc), "%s: Found good phase = %d\n",
78 mmc_hostname(mmc), phase);
79 if (start == -1)
80 start = phase;
81 end = phase;
82 range++;
83 if (phase == (SIRF_TUNING_COUNT - 1)
84 && range > longest_range)
85 tuning_value = (start + end) / 2;
86 } else {
87 dev_dbg(mmc_dev(mmc), "%s: Found bad phase = %d\n",
88 mmc_hostname(mmc), phase);
89 if (range > longest_range) {
90 tuning_value = (start + end) / 2;
91 longest_range = range;
92 }
93 start = -1;
94 end = range = 0;
95 }
96 } while (++phase < ARRAY_SIZE(tuned_phases));
97
98 if (tuned_phase_cnt && tuning_value > 0) {
99 /*
100 * Finally set the selected phase in delay
101 * line hw block.
102 */
103 phase = tuning_value;
104 sdhci_writel(host,
105 clock_setting | phase | (phase << 7) | (phase << 16),
106 SDHCI_CLK_DELAY_SETTING);
107
108 dev_dbg(mmc_dev(mmc), "%s: Setting the tuning phase to %d\n",
109 mmc_hostname(mmc), phase);
110 } else {
111 if (--tuning_seq_cnt)
112 goto retry;
113 /* Tuning failed */
114 dev_dbg(mmc_dev(mmc), "%s: No tuning point found\n",
115 mmc_hostname(mmc));
116 rc = -EIO;
117 }
118
119 return rc;
120}
121
52static struct sdhci_ops sdhci_sirf_ops = { 122static struct sdhci_ops sdhci_sirf_ops = {
123 .platform_execute_tuning = sdhci_sirf_execute_tuning,
53 .set_clock = sdhci_set_clock, 124 .set_clock = sdhci_set_clock,
54 .get_max_clock = sdhci_sirf_get_max_clk, 125 .get_max_clock = sdhci_sirf_get_max_clk,
55 .set_bus_width = sdhci_sirf_set_bus_width, 126 .set_bus_width = sdhci_sirf_set_bus_width,