diff options
author | Olof Johansson <olof@lixom.net> | 2011-10-16 19:54:51 -0400 |
---|---|---|
committer | Olof Johansson <olof@lixom.net> | 2012-02-06 21:24:59 -0500 |
commit | 17711dbf4788ded84470941ff63a7029f73ca654 (patch) | |
tree | 2a728096b0c3c67299bf47fb9a0069c7fbb9e67a /arch | |
parent | dee47183301983139fd0ed784d0defe0ba08f8f6 (diff) |
ARM: tegra: emc: convert tegra2_emc to a platform driver
This is the first step in making it device-tree aware and get rid of the
in-kernel EMC tables (of which there are none in mainline, thankfully).
Changes since v3:
* moved to devm_request_and_ioremap() in probe()
Changes since v2:
* D'oh -- missed a couple of variables that were added, never used and then
later removed in a later patch.
Changes since v1:
* Fixed messed up indentation
* Removed code that should be gone (was added here and removed later in series)
Signed-off-by: Olof Johansson <olof@lixom.net>
Acked-by: Stephen Warren <swarren@nvidia.com>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/arm/mach-tegra/tegra2_emc.c | 92 | ||||
-rw-r--r-- | arch/arm/mach-tegra/tegra2_emc.h | 11 |
2 files changed, 73 insertions, 30 deletions
diff --git a/arch/arm/mach-tegra/tegra2_emc.c b/arch/arm/mach-tegra/tegra2_emc.c index 0f7ae6e90b55..e6229bbbb83a 100644 --- a/arch/arm/mach-tegra/tegra2_emc.c +++ b/arch/arm/mach-tegra/tegra2_emc.c | |||
@@ -16,10 +16,13 @@ | |||
16 | */ | 16 | */ |
17 | 17 | ||
18 | #include <linux/kernel.h> | 18 | #include <linux/kernel.h> |
19 | #include <linux/device.h> | ||
19 | #include <linux/clk.h> | 20 | #include <linux/clk.h> |
20 | #include <linux/err.h> | 21 | #include <linux/err.h> |
21 | #include <linux/io.h> | 22 | #include <linux/io.h> |
22 | #include <linux/module.h> | 23 | #include <linux/module.h> |
24 | #include <linux/platform_device.h> | ||
25 | #include <linux/platform_data/tegra_emc.h> | ||
23 | 26 | ||
24 | #include <mach/iomap.h> | 27 | #include <mach/iomap.h> |
25 | 28 | ||
@@ -32,18 +35,17 @@ static bool emc_enable; | |||
32 | #endif | 35 | #endif |
33 | module_param(emc_enable, bool, 0644); | 36 | module_param(emc_enable, bool, 0644); |
34 | 37 | ||
35 | static void __iomem *emc = IO_ADDRESS(TEGRA_EMC_BASE); | 38 | static struct platform_device *emc_pdev; |
36 | static const struct tegra_emc_table *tegra_emc_table; | 39 | static void __iomem *emc_regbase; |
37 | static int tegra_emc_table_size; | ||
38 | 40 | ||
39 | static inline void emc_writel(u32 val, unsigned long addr) | 41 | static inline void emc_writel(u32 val, unsigned long addr) |
40 | { | 42 | { |
41 | writel(val, emc + addr); | 43 | writel(val, emc_regbase + addr); |
42 | } | 44 | } |
43 | 45 | ||
44 | static inline u32 emc_readl(unsigned long addr) | 46 | static inline u32 emc_readl(unsigned long addr) |
45 | { | 47 | { |
46 | return readl(emc + addr); | 48 | return readl(emc_regbase + addr); |
47 | } | 49 | } |
48 | 50 | ||
49 | static const unsigned long emc_reg_addr[TEGRA_EMC_NUM_REGS] = { | 51 | static const unsigned long emc_reg_addr[TEGRA_EMC_NUM_REGS] = { |
@@ -98,15 +100,15 @@ static const unsigned long emc_reg_addr[TEGRA_EMC_NUM_REGS] = { | |||
98 | /* Select the closest EMC rate that is higher than the requested rate */ | 100 | /* Select the closest EMC rate that is higher than the requested rate */ |
99 | long tegra_emc_round_rate(unsigned long rate) | 101 | long tegra_emc_round_rate(unsigned long rate) |
100 | { | 102 | { |
103 | struct tegra_emc_pdata *pdata; | ||
101 | int i; | 104 | int i; |
102 | int best = -1; | 105 | int best = -1; |
103 | unsigned long distance = ULONG_MAX; | 106 | unsigned long distance = ULONG_MAX; |
104 | 107 | ||
105 | if (!tegra_emc_table) | 108 | if (!emc_pdev) |
106 | return -EINVAL; | 109 | return -EINVAL; |
107 | 110 | ||
108 | if (!emc_enable) | 111 | pdata = emc_pdev->dev.platform_data; |
109 | return -EINVAL; | ||
110 | 112 | ||
111 | pr_debug("%s: %lu\n", __func__, rate); | 113 | pr_debug("%s: %lu\n", __func__, rate); |
112 | 114 | ||
@@ -116,10 +118,10 @@ long tegra_emc_round_rate(unsigned long rate) | |||
116 | */ | 118 | */ |
117 | rate = rate / 2 / 1000; | 119 | rate = rate / 2 / 1000; |
118 | 120 | ||
119 | for (i = 0; i < tegra_emc_table_size; i++) { | 121 | for (i = 0; i < pdata->num_tables; i++) { |
120 | if (tegra_emc_table[i].rate >= rate && | 122 | if (pdata->tables[i].rate >= rate && |
121 | (tegra_emc_table[i].rate - rate) < distance) { | 123 | (pdata->tables[i].rate - rate) < distance) { |
122 | distance = tegra_emc_table[i].rate - rate; | 124 | distance = pdata->tables[i].rate - rate; |
123 | best = i; | 125 | best = i; |
124 | } | 126 | } |
125 | } | 127 | } |
@@ -127,9 +129,9 @@ long tegra_emc_round_rate(unsigned long rate) | |||
127 | if (best < 0) | 129 | if (best < 0) |
128 | return -EINVAL; | 130 | return -EINVAL; |
129 | 131 | ||
130 | pr_debug("%s: using %lu\n", __func__, tegra_emc_table[best].rate); | 132 | pr_debug("%s: using %lu\n", __func__, pdata->tables[best].rate); |
131 | 133 | ||
132 | return tegra_emc_table[best].rate * 2 * 1000; | 134 | return pdata->tables[best].rate * 2 * 1000; |
133 | } | 135 | } |
134 | 136 | ||
135 | /* | 137 | /* |
@@ -142,37 +144,81 @@ long tegra_emc_round_rate(unsigned long rate) | |||
142 | */ | 144 | */ |
143 | int tegra_emc_set_rate(unsigned long rate) | 145 | int tegra_emc_set_rate(unsigned long rate) |
144 | { | 146 | { |
147 | struct tegra_emc_pdata *pdata; | ||
145 | int i; | 148 | int i; |
146 | int j; | 149 | int j; |
147 | 150 | ||
148 | if (!tegra_emc_table) | 151 | if (!emc_pdev) |
149 | return -EINVAL; | 152 | return -EINVAL; |
150 | 153 | ||
154 | pdata = emc_pdev->dev.platform_data; | ||
155 | |||
151 | /* | 156 | /* |
152 | * The EMC clock rate is twice the bus rate, and the bus rate is | 157 | * The EMC clock rate is twice the bus rate, and the bus rate is |
153 | * measured in kHz | 158 | * measured in kHz |
154 | */ | 159 | */ |
155 | rate = rate / 2 / 1000; | 160 | rate = rate / 2 / 1000; |
156 | 161 | ||
157 | for (i = 0; i < tegra_emc_table_size; i++) | 162 | for (i = 0; i < pdata->num_tables; i++) |
158 | if (tegra_emc_table[i].rate == rate) | 163 | if (pdata->tables[i].rate == rate) |
159 | break; | 164 | break; |
160 | 165 | ||
161 | if (i >= tegra_emc_table_size) | 166 | if (i >= pdata->num_tables) |
162 | return -EINVAL; | 167 | return -EINVAL; |
163 | 168 | ||
164 | pr_debug("%s: setting to %lu\n", __func__, rate); | 169 | pr_debug("%s: setting to %lu\n", __func__, rate); |
165 | 170 | ||
166 | for (j = 0; j < TEGRA_EMC_NUM_REGS; j++) | 171 | for (j = 0; j < TEGRA_EMC_NUM_REGS; j++) |
167 | emc_writel(tegra_emc_table[i].regs[j], emc_reg_addr[j]); | 172 | emc_writel(pdata->tables[i].regs[j], emc_reg_addr[j]); |
173 | |||
174 | emc_readl(pdata->tables[i].regs[TEGRA_EMC_NUM_REGS - 1]); | ||
175 | |||
176 | return 0; | ||
177 | } | ||
178 | |||
179 | static int __devinit tegra_emc_probe(struct platform_device *pdev) | ||
180 | { | ||
181 | struct tegra_emc_pdata *pdata; | ||
182 | struct resource *res; | ||
183 | |||
184 | if (!emc_enable) { | ||
185 | dev_err(&pdev->dev, "disabled per module parameter\n"); | ||
186 | return -ENODEV; | ||
187 | } | ||
188 | |||
189 | pdata = pdev->dev.platform_data; | ||
168 | 190 | ||
169 | emc_readl(tegra_emc_table[i].regs[TEGRA_EMC_NUM_REGS - 1]); | 191 | if (!pdata) { |
192 | dev_err(&pdev->dev, "missing platform data\n"); | ||
193 | return -ENXIO; | ||
194 | } | ||
195 | |||
196 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
197 | if (!res) { | ||
198 | dev_err(&pdev->dev, "missing register base\n"); | ||
199 | return -ENOMEM; | ||
200 | } | ||
201 | |||
202 | emc_regbase = devm_request_and_ioremap(&pdev->dev, res); | ||
203 | if (!emc_regbase) { | ||
204 | dev_err(&pdev->dev, "failed to remap registers\n"); | ||
205 | return -ENOMEM; | ||
206 | } | ||
207 | emc_pdev = pdev; | ||
170 | 208 | ||
171 | return 0; | 209 | return 0; |
172 | } | 210 | } |
173 | 211 | ||
174 | void tegra_init_emc(const struct tegra_emc_table *table, int table_size) | 212 | static struct platform_driver tegra_emc_driver = { |
213 | .driver = { | ||
214 | .name = "tegra-emc", | ||
215 | .owner = THIS_MODULE, | ||
216 | }, | ||
217 | .probe = tegra_emc_probe, | ||
218 | }; | ||
219 | |||
220 | static int __init tegra_emc_init(void) | ||
175 | { | 221 | { |
176 | tegra_emc_table = table; | 222 | return platform_driver_register(&tegra_emc_driver); |
177 | tegra_emc_table_size = table_size; | ||
178 | } | 223 | } |
224 | device_initcall(tegra_emc_init); | ||
diff --git a/arch/arm/mach-tegra/tegra2_emc.h b/arch/arm/mach-tegra/tegra2_emc.h index 19f08cb31603..f61409b54cb7 100644 --- a/arch/arm/mach-tegra/tegra2_emc.h +++ b/arch/arm/mach-tegra/tegra2_emc.h | |||
@@ -15,13 +15,10 @@ | |||
15 | * | 15 | * |
16 | */ | 16 | */ |
17 | 17 | ||
18 | #define TEGRA_EMC_NUM_REGS 46 | 18 | #ifndef __MACH_TEGRA_TEGRA2_EMC_H_ |
19 | 19 | #define __MACH_TEGRA_TEGRA2_EMC_H | |
20 | struct tegra_emc_table { | ||
21 | unsigned long rate; | ||
22 | u32 regs[TEGRA_EMC_NUM_REGS]; | ||
23 | }; | ||
24 | 20 | ||
25 | int tegra_emc_set_rate(unsigned long rate); | 21 | int tegra_emc_set_rate(unsigned long rate); |
26 | long tegra_emc_round_rate(unsigned long rate); | 22 | long tegra_emc_round_rate(unsigned long rate); |
27 | void tegra_init_emc(const struct tegra_emc_table *table, int table_size); | 23 | |
24 | #endif | ||