diff options
author | Ben Dooks <ben@simtec.co.uk> | 2005-01-23 19:37:04 -0500 |
---|---|---|
committer | Thomas Gleixner <tglx@mtd.linutronix.de> | 2005-05-23 05:33:47 -0400 |
commit | 99f2a8aea18c9779c141050c6f95a8f1da63bbe4 (patch) | |
tree | 5afcd7442131196b69cb6ed406729fa96bb7e0ab /drivers/mtd/maps/plat-ram.c | |
parent | a4ab4c5d32b66a440fb2e00f975f919f559f001d (diff) |
[MTD] Platform RAM Driver
Driver for generic RAM blocks which are exported by an platform_device
from the device driver system.
Signed-off-by: Ben Dooks <ben@simtec.co.uk>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'drivers/mtd/maps/plat-ram.c')
-rw-r--r-- | drivers/mtd/maps/plat-ram.c | 286 |
1 files changed, 286 insertions, 0 deletions
diff --git a/drivers/mtd/maps/plat-ram.c b/drivers/mtd/maps/plat-ram.c new file mode 100644 index 000000000000..808f94346add --- /dev/null +++ b/drivers/mtd/maps/plat-ram.c | |||
@@ -0,0 +1,286 @@ | |||
1 | /* drivers/mtd/maps/plat-ram.c | ||
2 | * | ||
3 | * (c) 2004-2005 Simtec Electronics | ||
4 | * http://www.simtec.co.uk/products/SWLINUX/ | ||
5 | * Ben Dooks <ben@simtec.co.uk> | ||
6 | * | ||
7 | * Generic platfrom device based RAM map | ||
8 | * | ||
9 | * $Id: plat-ram.c,v 1.1 2005/01/24 00:37:02 bjd Exp $ | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License as published by | ||
13 | * the Free Software Foundation; either version 2 of the License, or | ||
14 | * (at your option) any later version. | ||
15 | * | ||
16 | * This program is distributed in the hope that it will be useful, | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
19 | * GNU General Public License for more details. | ||
20 | * | ||
21 | * You should have received a copy of the GNU General Public License | ||
22 | * along with this program; if not, write to the Free Software | ||
23 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
24 | */ | ||
25 | |||
26 | #define DEBUG | ||
27 | |||
28 | #include <linux/module.h> | ||
29 | #include <linux/types.h> | ||
30 | #include <linux/init.h> | ||
31 | #include <linux/kernel.h> | ||
32 | #include <linux/string.h> | ||
33 | #include <linux/ioport.h> | ||
34 | #include <linux/device.h> | ||
35 | |||
36 | #include <linux/mtd/mtd.h> | ||
37 | #include <linux/mtd/map.h> | ||
38 | #include <linux/mtd/partitions.h> | ||
39 | #include <linux/mtd/plat-ram.h> | ||
40 | |||
41 | #include <asm/io.h> | ||
42 | |||
43 | /* private structure for each mtd platform ram device created */ | ||
44 | |||
45 | struct platram_info { | ||
46 | struct device *dev; | ||
47 | struct mtd_info *mtd; | ||
48 | struct map_info map; | ||
49 | struct mtd_partition *partitions; | ||
50 | struct resource *area; | ||
51 | struct platdata_mtd_ram *pdata; | ||
52 | }; | ||
53 | |||
54 | /* to_platram_info() | ||
55 | * | ||
56 | * device private data to struct platram_info conversion | ||
57 | */ | ||
58 | |||
59 | static inline struct platram_info *to_platram_info(struct device *dev) | ||
60 | { | ||
61 | return (struct platram_info *)dev_get_drvdata(dev); | ||
62 | } | ||
63 | |||
64 | /* platram_setrw | ||
65 | * | ||
66 | * call the platform device's set rw/ro control | ||
67 | * | ||
68 | * to = 0 => read-only | ||
69 | * = 1 => read-write | ||
70 | */ | ||
71 | |||
72 | static inline void platram_setrw(struct platram_info *info, int to) | ||
73 | { | ||
74 | if (info->pdata == NULL) | ||
75 | return; | ||
76 | |||
77 | if (info->pdata->set_rw != NULL) | ||
78 | (info->pdata->set_rw)(info->dev, to); | ||
79 | } | ||
80 | |||
81 | /* platram_remove | ||
82 | * | ||
83 | * called to remove the device from the driver's control | ||
84 | */ | ||
85 | |||
86 | static int platram_remove(struct device *dev) | ||
87 | { | ||
88 | struct platram_info *info = to_platram_info(dev); | ||
89 | |||
90 | dev_set_drvdata(dev, NULL); | ||
91 | |||
92 | dev_dbg(dev, "removing device\n"); | ||
93 | |||
94 | if (info == NULL) | ||
95 | return 0; | ||
96 | |||
97 | if (info->mtd) { | ||
98 | #ifdef CONFIG_MTD_PARTITIONS | ||
99 | if (info->partitions) { | ||
100 | del_mtd_partitions(info->mtd); | ||
101 | kfree(info->partitions); | ||
102 | } | ||
103 | #endif | ||
104 | del_mtd_device(info->mtd); | ||
105 | map_destroy(info->mtd); | ||
106 | } | ||
107 | |||
108 | /* ensure ram is left read-only */ | ||
109 | |||
110 | platram_setrw(info, PLATRAM_RO); | ||
111 | |||
112 | /* release resources */ | ||
113 | |||
114 | if (info->area) { | ||
115 | release_resource(info->area); | ||
116 | kfree(info->area); | ||
117 | } | ||
118 | |||
119 | if (info->map.virt != NULL) | ||
120 | iounmap(info->map.virt); | ||
121 | |||
122 | kfree(info); | ||
123 | |||
124 | return 0; | ||
125 | } | ||
126 | |||
127 | /* platram_probe | ||
128 | * | ||
129 | * called from device drive system when a device matching our | ||
130 | * driver is found. | ||
131 | */ | ||
132 | |||
133 | static int platram_probe(struct device *dev) | ||
134 | { | ||
135 | struct platform_device *pd = to_platform_device(dev); | ||
136 | struct platdata_mtd_ram *pdata; | ||
137 | struct platram_info *info; | ||
138 | struct resource *res; | ||
139 | int err = 0; | ||
140 | |||
141 | dev_dbg(dev, "probe entered\n"); | ||
142 | |||
143 | if (dev->platform_data == NULL) { | ||
144 | dev_err(dev, "no platform data supplied\n"); | ||
145 | err = -ENOENT; | ||
146 | goto exit_error; | ||
147 | } | ||
148 | |||
149 | pdata = dev->platform_data; | ||
150 | |||
151 | info = kmalloc(sizeof(*info), GFP_KERNEL); | ||
152 | if (info == NULL) { | ||
153 | dev_err(dev, "no memory for flash info\n"); | ||
154 | err = -ENOMEM; | ||
155 | goto exit_error; | ||
156 | } | ||
157 | |||
158 | memzero(info, sizeof(*info)); | ||
159 | dev_set_drvdata(dev, info); | ||
160 | |||
161 | info->dev = dev; | ||
162 | info->pdata = pdata; | ||
163 | |||
164 | /* get the resource for the memory mapping */ | ||
165 | |||
166 | res = platform_get_resource(pd, IORESOURCE_MEM, 0); | ||
167 | |||
168 | if (res == NULL) { | ||
169 | dev_err(dev, "no memory resource specified\n"); | ||
170 | err = -ENOENT; | ||
171 | goto exit_free; | ||
172 | } | ||
173 | |||
174 | dev_dbg(dev, "got platform resource %p (0x%lx)\n", res, res->start); | ||
175 | |||
176 | /* setup map parameters */ | ||
177 | |||
178 | info->map.phys = res->start; | ||
179 | info->map.size = (res->end - res->start) + 1; | ||
180 | info->map.name = pdata->mapname != NULL ? pdata->mapname : pd->name; | ||
181 | info->map.bankwidth = pdata->bankwidth; | ||
182 | |||
183 | /* register our usage of the memory area */ | ||
184 | |||
185 | info->area = request_mem_region(res->start, info->map.size, pd->name); | ||
186 | if (info->area == NULL) { | ||
187 | dev_err(dev, "failed to request memory region\n"); | ||
188 | err = -EIO; | ||
189 | goto exit_free; | ||
190 | } | ||
191 | |||
192 | /* remap the memory area */ | ||
193 | |||
194 | info->map.virt = ioremap(res->start, info->map.size); | ||
195 | dev_dbg(dev, "virt %p, %d bytes\n", info->map.virt, info->map.size); | ||
196 | |||
197 | if (info->map.virt == NULL) { | ||
198 | dev_err(dev, "failed to ioremap() region\n"); | ||
199 | err = -EIO; | ||
200 | goto exit_free; | ||
201 | } | ||
202 | |||
203 | { | ||
204 | unsigned int *p = (unsigned int *)info->map.virt; | ||
205 | printk("%08x %08x %08x %08x\n", | ||
206 | readl(p), readl(p+1), readl(p+2), readl(p+3)); | ||
207 | } | ||
208 | |||
209 | simple_map_init(&info->map); | ||
210 | |||
211 | dev_dbg(dev, "initialised map, probing for mtd\n"); | ||
212 | |||
213 | /* probe for the right mtd map driver */ | ||
214 | |||
215 | info->mtd = do_map_probe("map_ram" , &info->map); | ||
216 | if (info->mtd == NULL) { | ||
217 | dev_err(dev, "failed to probe for map_ram\n"); | ||
218 | err = -ENOMEM; | ||
219 | goto exit_free; | ||
220 | } | ||
221 | |||
222 | info->mtd->owner = THIS_MODULE; | ||
223 | |||
224 | platram_setrw(info, PLATRAM_RW); | ||
225 | |||
226 | /* check to see if there are any available partitions, or wether | ||
227 | * to add this device whole */ | ||
228 | |||
229 | #ifdef CONFIG_MTD_PARTITIONS | ||
230 | if (pdata->nr_partitions > 0) { | ||
231 | const char **probes = { NULL }; | ||
232 | |||
233 | if (pdata->probes) | ||
234 | probes = (const char **)pdata->probes; | ||
235 | |||
236 | err = parse_mtd_partitions(info->mtd, probes, | ||
237 | &info->partitions, 0); | ||
238 | if (err > 0) { | ||
239 | err = add_mtd_partitions(info->mtd, info->partitions, | ||
240 | err); | ||
241 | } | ||
242 | } | ||
243 | #endif /* CONFIG_MTD_PARTITIONS */ | ||
244 | |||
245 | if (add_mtd_device(info->mtd)) { | ||
246 | dev_err(dev, "add_mtd_device() failed\n"); | ||
247 | err = -ENOMEM; | ||
248 | } | ||
249 | |||
250 | dev_info(dev, "registered mtd device\n"); | ||
251 | return err; | ||
252 | |||
253 | exit_free: | ||
254 | platram_remove(dev); | ||
255 | exit_error: | ||
256 | return err; | ||
257 | } | ||
258 | |||
259 | /* device driver info */ | ||
260 | |||
261 | static struct device_driver platram_driver = { | ||
262 | .name = "mtd-ram", | ||
263 | .bus = &platform_bus_type, | ||
264 | .probe = platram_probe, | ||
265 | .remove = platram_remove, | ||
266 | }; | ||
267 | |||
268 | /* module init/exit */ | ||
269 | |||
270 | static int __init platram_init(void) | ||
271 | { | ||
272 | printk("Generic platform RAM MTD, (c) 2004 Simtec Electronics\n"); | ||
273 | return driver_register(&platram_driver); | ||
274 | } | ||
275 | |||
276 | static void __exit platram_exit(void) | ||
277 | { | ||
278 | driver_unregister(&platram_driver); | ||
279 | } | ||
280 | |||
281 | module_init(platram_init); | ||
282 | module_exit(platram_exit); | ||
283 | |||
284 | MODULE_LICENSE("GPL"); | ||
285 | MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>"); | ||
286 | MODULE_DESCRIPTION("MTD platform RAM map driver"); | ||