aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd/maps/physmap.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mtd/maps/physmap.c')
-rw-r--r--drivers/mtd/maps/physmap.c168
1 files changed, 108 insertions, 60 deletions
diff --git a/drivers/mtd/maps/physmap.c b/drivers/mtd/maps/physmap.c
index 28c5ffd75233..f00e04efbe28 100644
--- a/drivers/mtd/maps/physmap.c
+++ b/drivers/mtd/maps/physmap.c
@@ -20,11 +20,15 @@
20#include <linux/mtd/map.h> 20#include <linux/mtd/map.h>
21#include <linux/mtd/partitions.h> 21#include <linux/mtd/partitions.h>
22#include <linux/mtd/physmap.h> 22#include <linux/mtd/physmap.h>
23#include <linux/mtd/concat.h>
23#include <asm/io.h> 24#include <asm/io.h>
24 25
26#define MAX_RESOURCES 4
27
25struct physmap_flash_info { 28struct physmap_flash_info {
26 struct mtd_info *mtd; 29 struct mtd_info *mtd[MAX_RESOURCES];
27 struct map_info map; 30 struct mtd_info *cmtd;
31 struct map_info map[MAX_RESOURCES];
28 struct resource *res; 32 struct resource *res;
29#ifdef CONFIG_MTD_PARTITIONS 33#ifdef CONFIG_MTD_PARTITIONS
30 int nr_parts; 34 int nr_parts;
@@ -32,11 +36,11 @@ struct physmap_flash_info {
32#endif 36#endif
33}; 37};
34 38
35
36static int physmap_flash_remove(struct platform_device *dev) 39static int physmap_flash_remove(struct platform_device *dev)
37{ 40{
38 struct physmap_flash_info *info; 41 struct physmap_flash_info *info;
39 struct physmap_flash_data *physmap_data; 42 struct physmap_flash_data *physmap_data;
43 int i;
40 44
41 info = platform_get_drvdata(dev); 45 info = platform_get_drvdata(dev);
42 if (info == NULL) 46 if (info == NULL)
@@ -45,24 +49,33 @@ static int physmap_flash_remove(struct platform_device *dev)
45 49
46 physmap_data = dev->dev.platform_data; 50 physmap_data = dev->dev.platform_data;
47 51
48 if (info->mtd != NULL) { 52#ifdef CONFIG_MTD_CONCAT
53 if (info->cmtd != info->mtd[0]) {
54 del_mtd_device(info->cmtd);
55 mtd_concat_destroy(info->cmtd);
56 }
57#endif
58
59 for (i = 0; i < MAX_RESOURCES; i++) {
60 if (info->mtd[i] != NULL) {
49#ifdef CONFIG_MTD_PARTITIONS 61#ifdef CONFIG_MTD_PARTITIONS
50 if (info->nr_parts) { 62 if (info->nr_parts) {
51 del_mtd_partitions(info->mtd); 63 del_mtd_partitions(info->mtd[i]);
52 kfree(info->parts); 64 kfree(info->parts);
53 } else if (physmap_data->nr_parts) { 65 } else if (physmap_data->nr_parts) {
54 del_mtd_partitions(info->mtd); 66 del_mtd_partitions(info->mtd[i]);
55 } else { 67 } else {
56 del_mtd_device(info->mtd); 68 del_mtd_device(info->mtd[i]);
57 } 69 }
58#else 70#else
59 del_mtd_device(info->mtd); 71 del_mtd_device(info->mtd[i]);
60#endif 72#endif
61 map_destroy(info->mtd); 73 map_destroy(info->mtd[i]);
62 } 74 }
63 75
64 if (info->map.virt != NULL) 76 if (info->map[i].virt != NULL)
65 iounmap(info->map.virt); 77 iounmap(info->map[i].virt);
78 }
66 79
67 if (info->res != NULL) { 80 if (info->res != NULL) {
68 release_resource(info->res); 81 release_resource(info->res);
@@ -82,16 +95,14 @@ static int physmap_flash_probe(struct platform_device *dev)
82 struct physmap_flash_data *physmap_data; 95 struct physmap_flash_data *physmap_data;
83 struct physmap_flash_info *info; 96 struct physmap_flash_info *info;
84 const char **probe_type; 97 const char **probe_type;
85 int err; 98 int err = 0;
99 int i;
100 int devices_found = 0;
86 101
87 physmap_data = dev->dev.platform_data; 102 physmap_data = dev->dev.platform_data;
88 if (physmap_data == NULL) 103 if (physmap_data == NULL)
89 return -ENODEV; 104 return -ENODEV;
90 105
91 printk(KERN_NOTICE "physmap platform flash device: %.8llx at %.8llx\n",
92 (unsigned long long)(dev->resource->end - dev->resource->start + 1),
93 (unsigned long long)dev->resource->start);
94
95 info = kzalloc(sizeof(struct physmap_flash_info), GFP_KERNEL); 106 info = kzalloc(sizeof(struct physmap_flash_info), GFP_KERNEL);
96 if (info == NULL) { 107 if (info == NULL) {
97 err = -ENOMEM; 108 err = -ENOMEM;
@@ -100,56 +111,83 @@ static int physmap_flash_probe(struct platform_device *dev)
100 111
101 platform_set_drvdata(dev, info); 112 platform_set_drvdata(dev, info);
102 113
103 info->res = request_mem_region(dev->resource->start, 114 for (i = 0; i < dev->num_resources; i++) {
104 dev->resource->end - dev->resource->start + 1, 115 printk(KERN_NOTICE "physmap platform flash device: %.8llx at %.8llx\n",
105 dev->dev.bus_id); 116 (unsigned long long)(dev->resource[i].end - dev->resource[i].start + 1),
106 if (info->res == NULL) { 117 (unsigned long long)dev->resource[i].start);
107 dev_err(&dev->dev, "Could not reserve memory region\n"); 118
108 err = -ENOMEM; 119 info->res = request_mem_region(dev->resource[i].start,
109 goto err_out; 120 dev->resource[i].end - dev->resource[i].start + 1,
110 } 121 dev->dev.bus_id);
122 if (info->res == NULL) {
123 dev_err(&dev->dev, "Could not reserve memory region\n");
124 err = -ENOMEM;
125 goto err_out;
126 }
111 127
112 info->map.name = dev->dev.bus_id; 128 info->map[i].name = dev->dev.bus_id;
113 info->map.phys = dev->resource->start; 129 info->map[i].phys = dev->resource[i].start;
114 info->map.size = dev->resource->end - dev->resource->start + 1; 130 info->map[i].size = dev->resource[i].end - dev->resource[i].start + 1;
115 info->map.bankwidth = physmap_data->width; 131 info->map[i].bankwidth = physmap_data->width;
116 info->map.set_vpp = physmap_data->set_vpp; 132 info->map[i].set_vpp = physmap_data->set_vpp;
133
134 info->map[i].virt = ioremap(info->map[i].phys, info->map[i].size);
135 if (info->map[i].virt == NULL) {
136 dev_err(&dev->dev, "Failed to ioremap flash region\n");
137 err = EIO;
138 goto err_out;
139 }
117 140
118 info->map.virt = ioremap(info->map.phys, info->map.size); 141 simple_map_init(&info->map[i]);
119 if (info->map.virt == NULL) {
120 dev_err(&dev->dev, "Failed to ioremap flash region\n");
121 err = EIO;
122 goto err_out;
123 }
124 142
125 simple_map_init(&info->map); 143 probe_type = rom_probe_types;
144 for (; info->mtd[i] == NULL && *probe_type != NULL; probe_type++)
145 info->mtd[i] = do_map_probe(*probe_type, &info->map[i]);
146 if (info->mtd[i] == NULL) {
147 dev_err(&dev->dev, "map_probe failed\n");
148 err = -ENXIO;
149 goto err_out;
150 } else {
151 devices_found++;
152 }
153 info->mtd[i]->owner = THIS_MODULE;
154 }
126 155
127 probe_type = rom_probe_types; 156 if (devices_found == 1) {
128 for (; info->mtd == NULL && *probe_type != NULL; probe_type++) 157 info->cmtd = info->mtd[0];
129 info->mtd = do_map_probe(*probe_type, &info->map); 158 } else if (devices_found > 1) {
130 if (info->mtd == NULL) { 159 /*
131 dev_err(&dev->dev, "map_probe failed\n"); 160 * We detected multiple devices. Concatenate them together.
161 */
162#ifdef CONFIG_MTD_CONCAT
163 info->cmtd = mtd_concat_create(info->mtd, devices_found, dev->dev.bus_id);
164 if (info->cmtd == NULL)
165 err = -ENXIO;
166#else
167 printk(KERN_ERR "physmap-flash: multiple devices "
168 "found but MTD concat support disabled.\n");
132 err = -ENXIO; 169 err = -ENXIO;
133 goto err_out; 170#endif
134 } 171 }
135 info->mtd->owner = THIS_MODULE; 172 if (err)
173 goto err_out;
136 174
137#ifdef CONFIG_MTD_PARTITIONS 175#ifdef CONFIG_MTD_PARTITIONS
138 err = parse_mtd_partitions(info->mtd, part_probe_types, &info->parts, 0); 176 err = parse_mtd_partitions(info->cmtd, part_probe_types, &info->parts, 0);
139 if (err > 0) { 177 if (err > 0) {
140 add_mtd_partitions(info->mtd, info->parts, err); 178 add_mtd_partitions(info->cmtd, info->parts, err);
141 return 0; 179 return 0;
142 } 180 }
143 181
144 if (physmap_data->nr_parts) { 182 if (physmap_data->nr_parts) {
145 printk(KERN_NOTICE "Using physmap partition information\n"); 183 printk(KERN_NOTICE "Using physmap partition information\n");
146 add_mtd_partitions(info->mtd, physmap_data->parts, 184 add_mtd_partitions(info->cmtd, physmap_data->parts,
147 physmap_data->nr_parts); 185 physmap_data->nr_parts);
148 return 0; 186 return 0;
149 } 187 }
150#endif 188#endif
151 189
152 add_mtd_device(info->mtd); 190 add_mtd_device(info->cmtd);
153 return 0; 191 return 0;
154 192
155err_out: 193err_out:
@@ -162,9 +200,11 @@ static int physmap_flash_suspend(struct platform_device *dev, pm_message_t state
162{ 200{
163 struct physmap_flash_info *info = platform_get_drvdata(dev); 201 struct physmap_flash_info *info = platform_get_drvdata(dev);
164 int ret = 0; 202 int ret = 0;
203 int i;
165 204
166 if (info) 205 if (info)
167 ret = info->mtd->suspend(info->mtd); 206 for (i = 0; i < MAX_RESOURCES; i++)
207 ret |= info->mtd[i]->suspend(info->mtd[i]);
168 208
169 return ret; 209 return ret;
170} 210}
@@ -172,27 +212,35 @@ static int physmap_flash_suspend(struct platform_device *dev, pm_message_t state
172static int physmap_flash_resume(struct platform_device *dev) 212static int physmap_flash_resume(struct platform_device *dev)
173{ 213{
174 struct physmap_flash_info *info = platform_get_drvdata(dev); 214 struct physmap_flash_info *info = platform_get_drvdata(dev);
215 int i;
216
175 if (info) 217 if (info)
176 info->mtd->resume(info->mtd); 218 for (i = 0; i < MAX_RESOURCES; i++)
219 info->mtd[i]->resume(info->mtd[i]);
177 return 0; 220 return 0;
178} 221}
179 222
180static void physmap_flash_shutdown(struct platform_device *dev) 223static void physmap_flash_shutdown(struct platform_device *dev)
181{ 224{
182 struct physmap_flash_info *info = platform_get_drvdata(dev); 225 struct physmap_flash_info *info = platform_get_drvdata(dev);
183 if (info && info->mtd->suspend(info->mtd) == 0) 226 int i;
184 info->mtd->resume(info->mtd); 227
228 for (i = 0; i < MAX_RESOURCES; i++)
229 if (info && info->mtd[i]->suspend(info->mtd[i]) == 0)
230 info->mtd[i]->resume(info->mtd[i]);
185} 231}
232#else
233#define physmap_flash_suspend NULL
234#define physmap_flash_resume NULL
235#define physmap_flash_shutdown NULL
186#endif 236#endif
187 237
188static struct platform_driver physmap_flash_driver = { 238static struct platform_driver physmap_flash_driver = {
189 .probe = physmap_flash_probe, 239 .probe = physmap_flash_probe,
190 .remove = physmap_flash_remove, 240 .remove = physmap_flash_remove,
191#ifdef CONFIG_PM
192 .suspend = physmap_flash_suspend, 241 .suspend = physmap_flash_suspend,
193 .resume = physmap_flash_resume, 242 .resume = physmap_flash_resume,
194 .shutdown = physmap_flash_shutdown, 243 .shutdown = physmap_flash_shutdown,
195#endif
196 .driver = { 244 .driver = {
197 .name = "physmap-flash", 245 .name = "physmap-flash",
198 }, 246 },