diff options
author | Olof Johansson <olof@lixom.net> | 2011-10-17 19:05:22 -0400 |
---|---|---|
committer | Olof Johansson <olof@lixom.net> | 2012-02-06 21:24:59 -0500 |
commit | 941b8db1df8bfc29a88fc8e3e203289d84a3f64d (patch) | |
tree | bfed645eff99faf77ffb96c1b3656a5bf09d8c68 | |
parent | 17711dbf4788ded84470941ff63a7029f73ca654 (diff) |
ARM: tegra: emc: device tree support
Add device tree support to the emc driver, filling in the platform data
based on the DT bindings.
Changes since v1:
* Unmangled some messed up patch squashes, moving changes to earlier patches
* Flipped an of_property_read_u32 return value test
* Clarified clock settings message on case where no table is provided
Signed-off-by: Olof Johansson <olof@lixom.net>
Acked-by: Stephen Warren <swarren@nvidia.com>
-rw-r--r-- | arch/arm/mach-tegra/tegra2_emc.c | 146 |
1 files changed, 139 insertions, 7 deletions
diff --git a/arch/arm/mach-tegra/tegra2_emc.c b/arch/arm/mach-tegra/tegra2_emc.c index e6229bbbb83a..52df6ca36292 100644 --- a/arch/arm/mach-tegra/tegra2_emc.c +++ b/arch/arm/mach-tegra/tegra2_emc.c | |||
@@ -21,12 +21,14 @@ | |||
21 | #include <linux/err.h> | 21 | #include <linux/err.h> |
22 | #include <linux/io.h> | 22 | #include <linux/io.h> |
23 | #include <linux/module.h> | 23 | #include <linux/module.h> |
24 | #include <linux/of.h> | ||
24 | #include <linux/platform_device.h> | 25 | #include <linux/platform_device.h> |
25 | #include <linux/platform_data/tegra_emc.h> | 26 | #include <linux/platform_data/tegra_emc.h> |
26 | 27 | ||
27 | #include <mach/iomap.h> | 28 | #include <mach/iomap.h> |
28 | 29 | ||
29 | #include "tegra2_emc.h" | 30 | #include "tegra2_emc.h" |
31 | #include "fuse.h" | ||
30 | 32 | ||
31 | #ifdef CONFIG_TEGRA_EMC_SCALING_ENABLE | 33 | #ifdef CONFIG_TEGRA_EMC_SCALING_ENABLE |
32 | static bool emc_enable = true; | 34 | static bool emc_enable = true; |
@@ -176,6 +178,126 @@ int tegra_emc_set_rate(unsigned long rate) | |||
176 | return 0; | 178 | return 0; |
177 | } | 179 | } |
178 | 180 | ||
181 | #ifdef CONFIG_OF | ||
182 | static struct device_node *tegra_emc_ramcode_devnode(struct device_node *np) | ||
183 | { | ||
184 | struct device_node *iter; | ||
185 | u32 reg; | ||
186 | |||
187 | for_each_child_of_node(np, iter) { | ||
188 | if (of_property_read_u32(np, "nvidia,ram-code", ®)) | ||
189 | continue; | ||
190 | if (reg == tegra_bct_strapping) | ||
191 | return of_node_get(iter); | ||
192 | } | ||
193 | |||
194 | return NULL; | ||
195 | } | ||
196 | |||
197 | static struct tegra_emc_pdata *tegra_emc_dt_parse_pdata( | ||
198 | struct platform_device *pdev) | ||
199 | { | ||
200 | struct device_node *np = pdev->dev.of_node; | ||
201 | struct device_node *tnp, *iter; | ||
202 | struct tegra_emc_pdata *pdata; | ||
203 | int ret, i, num_tables; | ||
204 | |||
205 | if (!np) | ||
206 | return NULL; | ||
207 | |||
208 | if (of_find_property(np, "nvidia,use-ram-code", NULL)) { | ||
209 | tnp = tegra_emc_ramcode_devnode(np); | ||
210 | if (!tnp) | ||
211 | dev_warn(&pdev->dev, | ||
212 | "can't find emc table for ram-code 0x%02x\n", | ||
213 | tegra_bct_strapping); | ||
214 | } else | ||
215 | tnp = of_node_get(np); | ||
216 | |||
217 | if (!tnp) | ||
218 | return NULL; | ||
219 | |||
220 | num_tables = 0; | ||
221 | for_each_child_of_node(tnp, iter) | ||
222 | if (of_device_is_compatible(iter, "nvidia,tegra20-emc-table")) | ||
223 | num_tables++; | ||
224 | |||
225 | if (!num_tables) { | ||
226 | pdata = NULL; | ||
227 | goto out; | ||
228 | } | ||
229 | |||
230 | pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); | ||
231 | pdata->tables = devm_kzalloc(&pdev->dev, | ||
232 | sizeof(*pdata->tables) * num_tables, | ||
233 | GFP_KERNEL); | ||
234 | |||
235 | i = 0; | ||
236 | for_each_child_of_node(tnp, iter) { | ||
237 | u32 prop; | ||
238 | |||
239 | ret = of_property_read_u32(iter, "clock-frequency", &prop); | ||
240 | if (ret) { | ||
241 | dev_err(&pdev->dev, "no clock-frequency in %s\n", | ||
242 | iter->full_name); | ||
243 | continue; | ||
244 | } | ||
245 | pdata->tables[i].rate = prop; | ||
246 | |||
247 | ret = of_property_read_u32_array(iter, "nvidia,emc-registers", | ||
248 | pdata->tables[i].regs, | ||
249 | TEGRA_EMC_NUM_REGS); | ||
250 | if (ret) { | ||
251 | dev_err(&pdev->dev, | ||
252 | "malformed emc-registers property in %s\n", | ||
253 | iter->full_name); | ||
254 | continue; | ||
255 | } | ||
256 | |||
257 | i++; | ||
258 | } | ||
259 | pdata->num_tables = i; | ||
260 | |||
261 | out: | ||
262 | of_node_put(tnp); | ||
263 | return pdata; | ||
264 | } | ||
265 | #else | ||
266 | static struct tegra_emc_pdata *tegra_emc_dt_parse_pdata( | ||
267 | struct platform_device *pdev) | ||
268 | { | ||
269 | return NULL; | ||
270 | } | ||
271 | #endif | ||
272 | |||
273 | static struct tegra_emc_pdata __devinit *tegra_emc_fill_pdata(struct platform_device *pdev) | ||
274 | { | ||
275 | struct clk *c = clk_get_sys(NULL, "emc"); | ||
276 | struct tegra_emc_pdata *pdata; | ||
277 | unsigned long khz; | ||
278 | int i; | ||
279 | |||
280 | WARN_ON(pdev->dev.platform_data); | ||
281 | BUG_ON(IS_ERR_OR_NULL(c)); | ||
282 | |||
283 | pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); | ||
284 | pdata->tables = devm_kzalloc(&pdev->dev, sizeof(*pdata->tables), | ||
285 | GFP_KERNEL); | ||
286 | |||
287 | pdata->tables[0].rate = clk_get_rate(c); | ||
288 | |||
289 | for (i = 0; i < TEGRA_EMC_NUM_REGS; i++) | ||
290 | pdata->tables[0].regs[i] = emc_readl(emc_reg_addr[i]); | ||
291 | |||
292 | pdata->num_tables = 1; | ||
293 | |||
294 | khz = pdata->tables[0].rate / 1000; | ||
295 | dev_info(&pdev->dev, "no tables provided, using %ld kHz emc, " | ||
296 | "%ld kHz mem\n", khz, khz/2); | ||
297 | |||
298 | return pdata; | ||
299 | } | ||
300 | |||
179 | static int __devinit tegra_emc_probe(struct platform_device *pdev) | 301 | static int __devinit tegra_emc_probe(struct platform_device *pdev) |
180 | { | 302 | { |
181 | struct tegra_emc_pdata *pdata; | 303 | struct tegra_emc_pdata *pdata; |
@@ -186,13 +308,6 @@ static int __devinit tegra_emc_probe(struct platform_device *pdev) | |||
186 | return -ENODEV; | 308 | return -ENODEV; |
187 | } | 309 | } |
188 | 310 | ||
189 | pdata = pdev->dev.platform_data; | ||
190 | |||
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); | 311 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
197 | if (!res) { | 312 | if (!res) { |
198 | dev_err(&pdev->dev, "missing register base\n"); | 313 | dev_err(&pdev->dev, "missing register base\n"); |
@@ -204,15 +319,32 @@ static int __devinit tegra_emc_probe(struct platform_device *pdev) | |||
204 | dev_err(&pdev->dev, "failed to remap registers\n"); | 319 | dev_err(&pdev->dev, "failed to remap registers\n"); |
205 | return -ENOMEM; | 320 | return -ENOMEM; |
206 | } | 321 | } |
322 | |||
323 | pdata = pdev->dev.platform_data; | ||
324 | |||
325 | if (!pdata) | ||
326 | pdata = tegra_emc_dt_parse_pdata(pdev); | ||
327 | |||
328 | if (!pdata) | ||
329 | pdata = tegra_emc_fill_pdata(pdev); | ||
330 | |||
331 | pdev->dev.platform_data = pdata; | ||
332 | |||
207 | emc_pdev = pdev; | 333 | emc_pdev = pdev; |
208 | 334 | ||
209 | return 0; | 335 | return 0; |
210 | } | 336 | } |
211 | 337 | ||
338 | static struct of_device_id tegra_emc_of_match[] __devinitdata = { | ||
339 | { .compatible = "nvidia,tegra20-emc", }, | ||
340 | { }, | ||
341 | }; | ||
342 | |||
212 | static struct platform_driver tegra_emc_driver = { | 343 | static struct platform_driver tegra_emc_driver = { |
213 | .driver = { | 344 | .driver = { |
214 | .name = "tegra-emc", | 345 | .name = "tegra-emc", |
215 | .owner = THIS_MODULE, | 346 | .owner = THIS_MODULE, |
347 | .of_match_table = tegra_emc_of_match, | ||
216 | }, | 348 | }, |
217 | .probe = tegra_emc_probe, | 349 | .probe = tegra_emc_probe, |
218 | }; | 350 | }; |