[MTD] m25p80: chip erase != block erase != sector erase
[deliverable/linux.git] / drivers / mtd / maps / physmap.c
CommitLineData
1da177e4 1/*
1da177e4
LT
2 * Normal mappings of chips in physical memory
3 *
4 * Copyright (C) 2003 MontaVista Software Inc.
5 * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
6 *
7 * 031022 - [jsun] add run-time configure and partition setup
8 */
9
10#include <linux/module.h>
11#include <linux/types.h>
12#include <linux/kernel.h>
13#include <linux/init.h>
14#include <linux/slab.h>
73566edf
LB
15#include <linux/device.h>
16#include <linux/platform_device.h>
1da177e4
LT
17#include <linux/mtd/mtd.h>
18#include <linux/mtd/map.h>
1da177e4 19#include <linux/mtd/partitions.h>
2b9175c1 20#include <linux/mtd/physmap.h>
df66e716 21#include <linux/mtd/concat.h>
73566edf 22#include <asm/io.h>
1da177e4 23
df66e716
SR
24#define MAX_RESOURCES 4
25
73566edf 26struct physmap_flash_info {
df66e716
SR
27 struct mtd_info *mtd[MAX_RESOURCES];
28 struct mtd_info *cmtd;
29 struct map_info map[MAX_RESOURCES];
73566edf
LB
30 struct resource *res;
31#ifdef CONFIG_MTD_PARTITIONS
32 int nr_parts;
33 struct mtd_partition *parts;
34#endif
1da177e4
LT
35};
36
73566edf
LB
37static int physmap_flash_remove(struct platform_device *dev)
38{
39 struct physmap_flash_info *info;
40 struct physmap_flash_data *physmap_data;
df66e716 41 int i;
73566edf
LB
42
43 info = platform_get_drvdata(dev);
44 if (info == NULL)
45 return 0;
46 platform_set_drvdata(dev, NULL);
47
48 physmap_data = dev->dev.platform_data;
49
df66e716
SR
50#ifdef CONFIG_MTD_CONCAT
51 if (info->cmtd != info->mtd[0]) {
52 del_mtd_device(info->cmtd);
53 mtd_concat_destroy(info->cmtd);
54 }
55#endif
56
57 for (i = 0; i < MAX_RESOURCES; i++) {
58 if (info->mtd[i] != NULL) {
1da177e4 59#ifdef CONFIG_MTD_PARTITIONS
df66e716
SR
60 if (info->nr_parts) {
61 del_mtd_partitions(info->mtd[i]);
62 kfree(info->parts);
63 } else if (physmap_data->nr_parts) {
64 del_mtd_partitions(info->mtd[i]);
65 } else {
66 del_mtd_device(info->mtd[i]);
67 }
73566edf 68#else
df66e716 69 del_mtd_device(info->mtd[i]);
73566edf 70#endif
df66e716
SR
71 map_destroy(info->mtd[i]);
72 }
1da177e4 73
df66e716
SR
74 if (info->map[i].virt != NULL)
75 iounmap(info->map[i].virt);
76 }
1da177e4 77
73566edf
LB
78 if (info->res != NULL) {
79 release_resource(info->res);
80 kfree(info->res);
81 }
1da177e4 82
73566edf 83 return 0;
1da177e4 84}
1da177e4 85
73566edf
LB
86static const char *rom_probe_types[] = { "cfi_probe", "jedec_probe", "map_rom", NULL };
87#ifdef CONFIG_MTD_PARTITIONS
88static const char *part_probe_types[] = { "cmdlinepart", "RedBoot", NULL };
89#endif
90
91static int physmap_flash_probe(struct platform_device *dev)
1da177e4 92{
73566edf
LB
93 struct physmap_flash_data *physmap_data;
94 struct physmap_flash_info *info;
95 const char **probe_type;
df66e716
SR
96 int err = 0;
97 int i;
98 int devices_found = 0;
73566edf
LB
99
100 physmap_data = dev->dev.platform_data;
101 if (physmap_data == NULL)
102 return -ENODEV;
103
95b93a0c 104 info = kzalloc(sizeof(struct physmap_flash_info), GFP_KERNEL);
73566edf
LB
105 if (info == NULL) {
106 err = -ENOMEM;
107 goto err_out;
108 }
1da177e4 109
73566edf 110 platform_set_drvdata(dev, info);
1da177e4 111
df66e716
SR
112 for (i = 0; i < dev->num_resources; i++) {
113 printk(KERN_NOTICE "physmap platform flash device: %.8llx at %.8llx\n",
114 (unsigned long long)(dev->resource[i].end - dev->resource[i].start + 1),
115 (unsigned long long)dev->resource[i].start);
116
117 info->res = request_mem_region(dev->resource[i].start,
118 dev->resource[i].end - dev->resource[i].start + 1,
119 dev->dev.bus_id);
120 if (info->res == NULL) {
121 dev_err(&dev->dev, "Could not reserve memory region\n");
122 err = -ENOMEM;
123 goto err_out;
124 }
1da177e4 125
df66e716
SR
126 info->map[i].name = dev->dev.bus_id;
127 info->map[i].phys = dev->resource[i].start;
128 info->map[i].size = dev->resource[i].end - dev->resource[i].start + 1;
129 info->map[i].bankwidth = physmap_data->width;
130 info->map[i].set_vpp = physmap_data->set_vpp;
131
132 info->map[i].virt = ioremap(info->map[i].phys, info->map[i].size);
133 if (info->map[i].virt == NULL) {
134 dev_err(&dev->dev, "Failed to ioremap flash region\n");
135 err = EIO;
136 goto err_out;
137 }
73566edf 138
df66e716 139 simple_map_init(&info->map[i]);
1da177e4 140
df66e716
SR
141 probe_type = rom_probe_types;
142 for (; info->mtd[i] == NULL && *probe_type != NULL; probe_type++)
143 info->mtd[i] = do_map_probe(*probe_type, &info->map[i]);
144 if (info->mtd[i] == NULL) {
145 dev_err(&dev->dev, "map_probe failed\n");
146 err = -ENXIO;
147 goto err_out;
148 } else {
149 devices_found++;
150 }
151 info->mtd[i]->owner = THIS_MODULE;
152 }
73566edf 153
df66e716
SR
154 if (devices_found == 1) {
155 info->cmtd = info->mtd[0];
156 } else if (devices_found > 1) {
157 /*
158 * We detected multiple devices. Concatenate them together.
159 */
160#ifdef CONFIG_MTD_CONCAT
161 info->cmtd = mtd_concat_create(info->mtd, devices_found, dev->dev.bus_id);
162 if (info->cmtd == NULL)
163 err = -ENXIO;
164#else
165 printk(KERN_ERR "physmap-flash: multiple devices "
166 "found but MTD concat support disabled.\n");
73566edf 167 err = -ENXIO;
df66e716 168#endif
1da177e4 169 }
df66e716
SR
170 if (err)
171 goto err_out;
1da177e4
LT
172
173#ifdef CONFIG_MTD_PARTITIONS
df66e716 174 err = parse_mtd_partitions(info->cmtd, part_probe_types, &info->parts, 0);
73566edf 175 if (err > 0) {
df66e716 176 add_mtd_partitions(info->cmtd, info->parts, err);
73566edf
LB
177 return 0;
178 }
1da177e4 179
73566edf
LB
180 if (physmap_data->nr_parts) {
181 printk(KERN_NOTICE "Using physmap partition information\n");
df66e716
SR
182 add_mtd_partitions(info->cmtd, physmap_data->parts,
183 physmap_data->nr_parts);
73566edf
LB
184 return 0;
185 }
186#endif
187
df66e716 188 add_mtd_device(info->cmtd);
73566edf
LB
189 return 0;
190
191err_out:
192 physmap_flash_remove(dev);
193 return err;
194}
195
17c2dae3
LB
196#ifdef CONFIG_PM
197static int physmap_flash_suspend(struct platform_device *dev, pm_message_t state)
198{
199 struct physmap_flash_info *info = platform_get_drvdata(dev);
200 int ret = 0;
df66e716 201 int i;
17c2dae3 202
4a5691c0 203 for (i = 0; i < MAX_RESOURCES && info->mtd[i]; i++)
4b5e33a7
UKK
204 if (info->mtd[i]->suspend) {
205 ret = info->mtd[i]->suspend(info->mtd[i]);
206 if (ret)
207 goto fail;
208 }
209
210 return 0;
211fail:
212 for (--i; i >= 0; --i)
213 if (info->mtd[i]->suspend) {
214 BUG_ON(!info->mtd[i]->resume);
215 info->mtd[i]->resume(info->mtd[i]);
216 }
17c2dae3
LB
217
218 return ret;
219}
220
221static int physmap_flash_resume(struct platform_device *dev)
222{
223 struct physmap_flash_info *info = platform_get_drvdata(dev);
df66e716
SR
224 int i;
225
4a5691c0 226 for (i = 0; i < MAX_RESOURCES && info->mtd[i]; i++)
7b249191
RJ
227 if (info->mtd[i]->resume)
228 info->mtd[i]->resume(info->mtd[i]);
4a5691c0 229
17c2dae3
LB
230 return 0;
231}
232
233static void physmap_flash_shutdown(struct platform_device *dev)
234{
235 struct physmap_flash_info *info = platform_get_drvdata(dev);
df66e716
SR
236 int i;
237
4a5691c0 238 for (i = 0; i < MAX_RESOURCES && info->mtd[i]; i++)
7b249191
RJ
239 if (info->mtd[i]->suspend && info->mtd[i]->resume)
240 if (info->mtd[i]->suspend(info->mtd[i]) == 0)
241 info->mtd[i]->resume(info->mtd[i]);
17c2dae3 242}
d5476689 243#else
244#define physmap_flash_suspend NULL
245#define physmap_flash_resume NULL
246#define physmap_flash_shutdown NULL
17c2dae3
LB
247#endif
248
73566edf
LB
249static struct platform_driver physmap_flash_driver = {
250 .probe = physmap_flash_probe,
251 .remove = physmap_flash_remove,
17c2dae3
LB
252 .suspend = physmap_flash_suspend,
253 .resume = physmap_flash_resume,
254 .shutdown = physmap_flash_shutdown,
73566edf
LB
255 .driver = {
256 .name = "physmap-flash",
41d867c9 257 .owner = THIS_MODULE,
73566edf
LB
258 },
259};
1da177e4 260
1da177e4 261
73566edf
LB
262#ifdef CONFIG_MTD_PHYSMAP_LEN
263#if CONFIG_MTD_PHYSMAP_LEN != 0
264#warning using PHYSMAP compat code
265#define PHYSMAP_COMPAT
266#endif
1da177e4 267#endif
1da177e4 268
73566edf
LB
269#ifdef PHYSMAP_COMPAT
270static struct physmap_flash_data physmap_flash_data = {
271 .width = CONFIG_MTD_PHYSMAP_BANKWIDTH,
272};
1da177e4 273
73566edf
LB
274static struct resource physmap_flash_resource = {
275 .start = CONFIG_MTD_PHYSMAP_START,
6d4f8224 276 .end = CONFIG_MTD_PHYSMAP_START + CONFIG_MTD_PHYSMAP_LEN - 1,
73566edf
LB
277 .flags = IORESOURCE_MEM,
278};
1da177e4 279
73566edf
LB
280static struct platform_device physmap_flash = {
281 .name = "physmap-flash",
282 .id = 0,
283 .dev = {
284 .platform_data = &physmap_flash_data,
285 },
286 .num_resources = 1,
287 .resource = &physmap_flash_resource,
288};
289
290void physmap_configure(unsigned long addr, unsigned long size,
291 int bankwidth, void (*set_vpp)(struct map_info *, int))
1da177e4 292{
73566edf
LB
293 physmap_flash_resource.start = addr;
294 physmap_flash_resource.end = addr + size - 1;
295 physmap_flash_data.width = bankwidth;
296 physmap_flash_data.set_vpp = set_vpp;
297}
298
1da177e4 299#ifdef CONFIG_MTD_PARTITIONS
73566edf
LB
300void physmap_set_partitions(struct mtd_partition *parts, int num_parts)
301{
302 physmap_flash_data.nr_parts = num_parts;
303 physmap_flash_data.parts = parts;
304}
305#endif
1da177e4 306#endif
1da177e4 307
73566edf
LB
308static int __init physmap_init(void)
309{
310 int err;
311
312 err = platform_driver_register(&physmap_flash_driver);
313#ifdef PHYSMAP_COMPAT
314 if (err == 0)
315 platform_device_register(&physmap_flash);
316#endif
317
318 return err;
1da177e4
LT
319}
320
73566edf
LB
321static void __exit physmap_exit(void)
322{
323#ifdef PHYSMAP_COMPAT
324 platform_device_unregister(&physmap_flash);
325#endif
326 platform_driver_unregister(&physmap_flash_driver);
327}
1da177e4 328
73566edf
LB
329module_init(physmap_init);
330module_exit(physmap_exit);
1da177e4
LT
331
332MODULE_LICENSE("GPL");
333MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
334MODULE_DESCRIPTION("Generic configurable MTD map driver");
41d867c9
KS
335
336/* legacy platform drivers can't hotplug or coldplg */
337#ifndef PHYSMAP_COMPAT
338/* work with hotplug and coldplug */
339MODULE_ALIAS("platform:physmap-flash");
340#endif
341
This page took 0.320253 seconds and 5 git commands to generate.