aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorOlof Johansson <olof@lixom.net>2011-10-16 19:54:51 -0400
committerOlof Johansson <olof@lixom.net>2012-02-06 21:24:59 -0500
commit17711dbf4788ded84470941ff63a7029f73ca654 (patch)
tree2a728096b0c3c67299bf47fb9a0069c7fbb9e67a /arch
parentdee47183301983139fd0ed784d0defe0ba08f8f6 (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.c92
-rw-r--r--arch/arm/mach-tegra/tegra2_emc.h11
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
33module_param(emc_enable, bool, 0644); 36module_param(emc_enable, bool, 0644);
34 37
35static void __iomem *emc = IO_ADDRESS(TEGRA_EMC_BASE); 38static struct platform_device *emc_pdev;
36static const struct tegra_emc_table *tegra_emc_table; 39static void __iomem *emc_regbase;
37static int tegra_emc_table_size;
38 40
39static inline void emc_writel(u32 val, unsigned long addr) 41static 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
44static inline u32 emc_readl(unsigned long addr) 46static inline u32 emc_readl(unsigned long addr)
45{ 47{
46 return readl(emc + addr); 48 return readl(emc_regbase + addr);
47} 49}
48 50
49static const unsigned long emc_reg_addr[TEGRA_EMC_NUM_REGS] = { 51static 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 */
99long tegra_emc_round_rate(unsigned long rate) 101long 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 */
143int tegra_emc_set_rate(unsigned long rate) 145int 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
179static 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
174void tegra_init_emc(const struct tegra_emc_table *table, int table_size) 212static struct platform_driver tegra_emc_driver = {
213 .driver = {
214 .name = "tegra-emc",
215 .owner = THIS_MODULE,
216 },
217 .probe = tegra_emc_probe,
218};
219
220static 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}
224device_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
20struct tegra_emc_table {
21 unsigned long rate;
22 u32 regs[TEGRA_EMC_NUM_REGS];
23};
24 20
25int tegra_emc_set_rate(unsigned long rate); 21int tegra_emc_set_rate(unsigned long rate);
26long tegra_emc_round_rate(unsigned long rate); 22long tegra_emc_round_rate(unsigned long rate);
27void tegra_init_emc(const struct tegra_emc_table *table, int table_size); 23
24#endif