diff options
-rw-r--r-- | drivers/mmc/host/sdhci-sirf.c | 71 |
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 | ||
20 | struct sdhci_sirf_priv { | 22 | struct 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 | ||
54 | static 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 | |||
67 | retry: | ||
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 | |||
52 | static struct sdhci_ops sdhci_sirf_ops = { | 122 | static 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, |