aboutsummaryrefslogtreecommitdiffstats
path: root/arch/avr32/mach-at32ap/hsmc.c
diff options
context:
space:
mode:
authorHaavard Skinnemoen <hskinnemoen@atmel.com>2006-09-26 02:32:16 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-09-26 11:48:54 -0400
commitbc157b75960f1f33566074e820342690216629b9 (patch)
tree3f494ec585eb4bf3e7def5de2b2455b13b5c42c8 /arch/avr32/mach-at32ap/hsmc.c
parent5f97f7f9400de47ae837170bb274e90ad3934386 (diff)
[PATCH] AVR32 MTD: Static Memory Controller driver
This patchset adds the necessary drivers and infrastructure to access the external flash on the ATSTK1000 board through the MTD subsystem. With this stuff in place, it will be possible to use a jffs2 filesystem stored in the external flash as a root filesystem. It might also be possible to update the boot loader if you drop the write protection of partition 0. As suggested by David Woodhouse, I reworked the patches to use the physmap driver instead of introducing a separate mapping driver for the ATSTK1000. I've also cleaned up the hsmc header by removing useless comments and converting spaces to tabs (my headerfile generator needs some work.) Unfortunately, I couldn't unlock the flash in fixup_use_atmel_lock because the erase regions hadn't been set up yet, so I had to do it from cfi_amdstd_setup instead. This patch: This adds a simple API for configuring the static memory controller along with an implementation for the Atmel HSMC. Signed-off-by: Haavard Skinnemoen <hskinnemoen@atmel.com> Cc: David Woodhouse <dwmw2@infradead.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch/avr32/mach-at32ap/hsmc.c')
-rw-r--r--arch/avr32/mach-at32ap/hsmc.c164
1 files changed, 164 insertions, 0 deletions
diff --git a/arch/avr32/mach-at32ap/hsmc.c b/arch/avr32/mach-at32ap/hsmc.c
new file mode 100644
index 000000000000..7691721928a7
--- /dev/null
+++ b/arch/avr32/mach-at32ap/hsmc.c
@@ -0,0 +1,164 @@
1/*
2 * Static Memory Controller for AT32 chips
3 *
4 * Copyright (C) 2006 Atmel Corporation
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10#define DEBUG
11#include <linux/clk.h>
12#include <linux/err.h>
13#include <linux/init.h>
14#include <linux/module.h>
15#include <linux/platform_device.h>
16
17#include <asm/io.h>
18#include <asm/arch/smc.h>
19
20#include "hsmc.h"
21
22#define NR_CHIP_SELECTS 6
23
24struct hsmc {
25 void __iomem *regs;
26 struct clk *pclk;
27 struct clk *mck;
28};
29
30static struct hsmc *hsmc;
31
32int smc_set_configuration(int cs, const struct smc_config *config)
33{
34 unsigned long mul;
35 unsigned long offset;
36 u32 setup, pulse, cycle, mode;
37
38 if (!hsmc)
39 return -ENODEV;
40 if (cs >= NR_CHIP_SELECTS)
41 return -EINVAL;
42
43 /*
44 * cycles = x / T = x * f
45 * = ((x * 1000000000) * ((f * 65536) / 1000000000)) / 65536
46 * = ((x * 1000000000) * (((f / 10000) * 65536) / 100000)) / 65536
47 */
48 mul = (clk_get_rate(hsmc->mck) / 10000) << 16;
49 mul /= 100000;
50
51#define ns2cyc(x) ((((x) * mul) + 65535) >> 16)
52
53 setup = (HSMC_BF(NWE_SETUP, ns2cyc(config->nwe_setup))
54 | HSMC_BF(NCS_WR_SETUP, ns2cyc(config->ncs_write_setup))
55 | HSMC_BF(NRD_SETUP, ns2cyc(config->nrd_setup))
56 | HSMC_BF(NCS_RD_SETUP, ns2cyc(config->ncs_read_setup)));
57 pulse = (HSMC_BF(NWE_PULSE, ns2cyc(config->nwe_pulse))
58 | HSMC_BF(NCS_WR_PULSE, ns2cyc(config->ncs_write_pulse))
59 | HSMC_BF(NRD_PULSE, ns2cyc(config->nrd_pulse))
60 | HSMC_BF(NCS_RD_PULSE, ns2cyc(config->ncs_read_pulse)));
61 cycle = (HSMC_BF(NWE_CYCLE, ns2cyc(config->write_cycle))
62 | HSMC_BF(NRD_CYCLE, ns2cyc(config->read_cycle)));
63
64 switch (config->bus_width) {
65 case 1:
66 mode = HSMC_BF(DBW, HSMC_DBW_8_BITS);
67 break;
68 case 2:
69 mode = HSMC_BF(DBW, HSMC_DBW_16_BITS);
70 break;
71 case 4:
72 mode = HSMC_BF(DBW, HSMC_DBW_32_BITS);
73 break;
74 default:
75 return -EINVAL;
76 }
77
78 if (config->nrd_controlled)
79 mode |= HSMC_BIT(READ_MODE);
80 if (config->nwe_controlled)
81 mode |= HSMC_BIT(WRITE_MODE);
82 if (config->byte_write)
83 mode |= HSMC_BIT(BAT);
84
85 pr_debug("smc cs%d: setup/%08x pulse/%08x cycle/%08x mode/%08x\n",
86 cs, setup, pulse, cycle, mode);
87
88 offset = cs * 0x10;
89 hsmc_writel(hsmc, SETUP0 + offset, setup);
90 hsmc_writel(hsmc, PULSE0 + offset, pulse);
91 hsmc_writel(hsmc, CYCLE0 + offset, cycle);
92 hsmc_writel(hsmc, MODE0 + offset, mode);
93 hsmc_readl(hsmc, MODE0); /* I/O barrier */
94
95 return 0;
96}
97EXPORT_SYMBOL(smc_set_configuration);
98
99static int hsmc_probe(struct platform_device *pdev)
100{
101 struct resource *regs;
102 struct clk *pclk, *mck;
103 int ret;
104
105 if (hsmc)
106 return -EBUSY;
107
108 regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
109 if (!regs)
110 return -ENXIO;
111 pclk = clk_get(&pdev->dev, "pclk");
112 if (IS_ERR(pclk))
113 return PTR_ERR(pclk);
114 mck = clk_get(&pdev->dev, "mck");
115 if (IS_ERR(mck)) {
116 ret = PTR_ERR(mck);
117 goto out_put_pclk;
118 }
119
120 ret = -ENOMEM;
121 hsmc = kzalloc(sizeof(struct hsmc), GFP_KERNEL);
122 if (!hsmc)
123 goto out_put_clocks;
124
125 clk_enable(pclk);
126 clk_enable(mck);
127
128 hsmc->pclk = pclk;
129 hsmc->mck = mck;
130 hsmc->regs = ioremap(regs->start, regs->end - regs->start + 1);
131 if (!hsmc->regs)
132 goto out_disable_clocks;
133
134 dev_info(&pdev->dev, "Atmel Static Memory Controller at 0x%08lx\n",
135 (unsigned long)regs->start);
136
137 platform_set_drvdata(pdev, hsmc);
138
139 return 0;
140
141out_disable_clocks:
142 clk_disable(mck);
143 clk_disable(pclk);
144 kfree(hsmc);
145out_put_clocks:
146 clk_put(mck);
147out_put_pclk:
148 clk_put(pclk);
149 hsmc = NULL;
150 return ret;
151}
152
153static struct platform_driver hsmc_driver = {
154 .probe = hsmc_probe,
155 .driver = {
156 .name = "smc",
157 },
158};
159
160static int __init hsmc_init(void)
161{
162 return platform_driver_register(&hsmc_driver);
163}
164arch_initcall(hsmc_init);