diff options
Diffstat (limited to 'drivers/mtd/maps/sa1100-flash.c')
-rw-r--r-- | drivers/mtd/maps/sa1100-flash.c | 78 |
1 files changed, 53 insertions, 25 deletions
diff --git a/drivers/mtd/maps/sa1100-flash.c b/drivers/mtd/maps/sa1100-flash.c index 52385705da09..c8d0da19d897 100644 --- a/drivers/mtd/maps/sa1100-flash.c +++ b/drivers/mtd/maps/sa1100-flash.c | |||
@@ -13,7 +13,7 @@ | |||
13 | #include <linux/init.h> | 13 | #include <linux/init.h> |
14 | #include <linux/errno.h> | 14 | #include <linux/errno.h> |
15 | #include <linux/slab.h> | 15 | #include <linux/slab.h> |
16 | #include <linux/device.h> | 16 | #include <linux/platform_device.h> |
17 | #include <linux/err.h> | 17 | #include <linux/err.h> |
18 | 18 | ||
19 | #include <linux/mtd/mtd.h> | 19 | #include <linux/mtd/mtd.h> |
@@ -21,7 +21,7 @@ | |||
21 | #include <linux/mtd/partitions.h> | 21 | #include <linux/mtd/partitions.h> |
22 | #include <linux/mtd/concat.h> | 22 | #include <linux/mtd/concat.h> |
23 | 23 | ||
24 | #include <asm/mach-types.h> | 24 | #include <asm/hardware.h> |
25 | #include <asm/io.h> | 25 | #include <asm/io.h> |
26 | #include <asm/sizes.h> | 26 | #include <asm/sizes.h> |
27 | #include <asm/mach/flash.h> | 27 | #include <asm/mach/flash.h> |
@@ -130,20 +130,21 @@ struct sa_subdev_info { | |||
130 | char name[16]; | 130 | char name[16]; |
131 | struct map_info map; | 131 | struct map_info map; |
132 | struct mtd_info *mtd; | 132 | struct mtd_info *mtd; |
133 | struct flash_platform_data *data; | 133 | struct flash_platform_data *plat; |
134 | }; | 134 | }; |
135 | 135 | ||
136 | struct sa_info { | 136 | struct sa_info { |
137 | struct mtd_partition *parts; | 137 | struct mtd_partition *parts; |
138 | struct mtd_info *mtd; | 138 | struct mtd_info *mtd; |
139 | int num_subdev; | 139 | int num_subdev; |
140 | unsigned int nr_parts; | ||
140 | struct sa_subdev_info subdev[0]; | 141 | struct sa_subdev_info subdev[0]; |
141 | }; | 142 | }; |
142 | 143 | ||
143 | static void sa1100_set_vpp(struct map_info *map, int on) | 144 | static void sa1100_set_vpp(struct map_info *map, int on) |
144 | { | 145 | { |
145 | struct sa_subdev_info *subdev = container_of(map, struct sa_subdev_info, map); | 146 | struct sa_subdev_info *subdev = container_of(map, struct sa_subdev_info, map); |
146 | subdev->data->set_vpp(on); | 147 | subdev->plat->set_vpp(on); |
147 | } | 148 | } |
148 | 149 | ||
149 | static void sa1100_destroy_subdev(struct sa_subdev_info *subdev) | 150 | static void sa1100_destroy_subdev(struct sa_subdev_info *subdev) |
@@ -187,7 +188,7 @@ static int sa1100_probe_subdev(struct sa_subdev_info *subdev, struct resource *r | |||
187 | goto out; | 188 | goto out; |
188 | } | 189 | } |
189 | 190 | ||
190 | if (subdev->data->set_vpp) | 191 | if (subdev->plat->set_vpp) |
191 | subdev->map.set_vpp = sa1100_set_vpp; | 192 | subdev->map.set_vpp = sa1100_set_vpp; |
192 | 193 | ||
193 | subdev->map.phys = phys; | 194 | subdev->map.phys = phys; |
@@ -204,7 +205,7 @@ static int sa1100_probe_subdev(struct sa_subdev_info *subdev, struct resource *r | |||
204 | * Now let's probe for the actual flash. Do it here since | 205 | * Now let's probe for the actual flash. Do it here since |
205 | * specific machine settings might have been set above. | 206 | * specific machine settings might have been set above. |
206 | */ | 207 | */ |
207 | subdev->mtd = do_map_probe(subdev->data->map_name, &subdev->map); | 208 | subdev->mtd = do_map_probe(subdev->plat->map_name, &subdev->map); |
208 | if (subdev->mtd == NULL) { | 209 | if (subdev->mtd == NULL) { |
209 | ret = -ENXIO; | 210 | ret = -ENXIO; |
210 | goto err; | 211 | goto err; |
@@ -223,13 +224,17 @@ static int sa1100_probe_subdev(struct sa_subdev_info *subdev, struct resource *r | |||
223 | return ret; | 224 | return ret; |
224 | } | 225 | } |
225 | 226 | ||
226 | static void sa1100_destroy(struct sa_info *info) | 227 | static void sa1100_destroy(struct sa_info *info, struct flash_platform_data *plat) |
227 | { | 228 | { |
228 | int i; | 229 | int i; |
229 | 230 | ||
230 | if (info->mtd) { | 231 | if (info->mtd) { |
231 | del_mtd_partitions(info->mtd); | 232 | if (info->nr_parts == 0) |
232 | 233 | del_mtd_device(info->mtd); | |
234 | #ifdef CONFIG_MTD_PARTITIONS | ||
235 | else | ||
236 | del_mtd_partitions(info->mtd); | ||
237 | #endif | ||
233 | #ifdef CONFIG_MTD_CONCAT | 238 | #ifdef CONFIG_MTD_CONCAT |
234 | if (info->mtd != info->subdev[0].mtd) | 239 | if (info->mtd != info->subdev[0].mtd) |
235 | mtd_concat_destroy(info->mtd); | 240 | mtd_concat_destroy(info->mtd); |
@@ -242,10 +247,13 @@ static void sa1100_destroy(struct sa_info *info) | |||
242 | for (i = info->num_subdev - 1; i >= 0; i--) | 247 | for (i = info->num_subdev - 1; i >= 0; i--) |
243 | sa1100_destroy_subdev(&info->subdev[i]); | 248 | sa1100_destroy_subdev(&info->subdev[i]); |
244 | kfree(info); | 249 | kfree(info); |
250 | |||
251 | if (plat->exit) | ||
252 | plat->exit(); | ||
245 | } | 253 | } |
246 | 254 | ||
247 | static struct sa_info *__init | 255 | static struct sa_info *__init |
248 | sa1100_setup_mtd(struct platform_device *pdev, struct flash_platform_data *flash) | 256 | sa1100_setup_mtd(struct platform_device *pdev, struct flash_platform_data *plat) |
249 | { | 257 | { |
250 | struct sa_info *info; | 258 | struct sa_info *info; |
251 | int nr, size, i, ret = 0; | 259 | int nr, size, i, ret = 0; |
@@ -275,6 +283,12 @@ sa1100_setup_mtd(struct platform_device *pdev, struct flash_platform_data *flash | |||
275 | 283 | ||
276 | memset(info, 0, size); | 284 | memset(info, 0, size); |
277 | 285 | ||
286 | if (plat->init) { | ||
287 | ret = plat->init(); | ||
288 | if (ret) | ||
289 | goto err; | ||
290 | } | ||
291 | |||
278 | /* | 292 | /* |
279 | * Claim and then map the memory regions. | 293 | * Claim and then map the memory regions. |
280 | */ | 294 | */ |
@@ -287,8 +301,8 @@ sa1100_setup_mtd(struct platform_device *pdev, struct flash_platform_data *flash | |||
287 | break; | 301 | break; |
288 | 302 | ||
289 | subdev->map.name = subdev->name; | 303 | subdev->map.name = subdev->name; |
290 | sprintf(subdev->name, "sa1100-%d", i); | 304 | sprintf(subdev->name, "%s-%d", plat->name, i); |
291 | subdev->data = flash; | 305 | subdev->plat = plat; |
292 | 306 | ||
293 | ret = sa1100_probe_subdev(subdev, res); | 307 | ret = sa1100_probe_subdev(subdev, res); |
294 | if (ret) | 308 | if (ret) |
@@ -309,7 +323,7 @@ sa1100_setup_mtd(struct platform_device *pdev, struct flash_platform_data *flash | |||
309 | * otherwise fail. Either way, it'll be called "sa1100". | 323 | * otherwise fail. Either way, it'll be called "sa1100". |
310 | */ | 324 | */ |
311 | if (info->num_subdev == 1) { | 325 | if (info->num_subdev == 1) { |
312 | strcpy(info->subdev[0].name, "sa1100"); | 326 | strcpy(info->subdev[0].name, plat->name); |
313 | info->mtd = info->subdev[0].mtd; | 327 | info->mtd = info->subdev[0].mtd; |
314 | ret = 0; | 328 | ret = 0; |
315 | } else if (info->num_subdev > 1) { | 329 | } else if (info->num_subdev > 1) { |
@@ -322,7 +336,7 @@ sa1100_setup_mtd(struct platform_device *pdev, struct flash_platform_data *flash | |||
322 | cdev[i] = info->subdev[i].mtd; | 336 | cdev[i] = info->subdev[i].mtd; |
323 | 337 | ||
324 | info->mtd = mtd_concat_create(cdev, info->num_subdev, | 338 | info->mtd = mtd_concat_create(cdev, info->num_subdev, |
325 | "sa1100"); | 339 | plat->name); |
326 | if (info->mtd == NULL) | 340 | if (info->mtd == NULL) |
327 | ret = -ENXIO; | 341 | ret = -ENXIO; |
328 | #else | 342 | #else |
@@ -336,7 +350,7 @@ sa1100_setup_mtd(struct platform_device *pdev, struct flash_platform_data *flash | |||
336 | return info; | 350 | return info; |
337 | 351 | ||
338 | err: | 352 | err: |
339 | sa1100_destroy(info); | 353 | sa1100_destroy(info, plat); |
340 | out: | 354 | out: |
341 | return ERR_PTR(ret); | 355 | return ERR_PTR(ret); |
342 | } | 356 | } |
@@ -346,16 +360,16 @@ static const char *part_probes[] = { "cmdlinepart", "RedBoot", NULL }; | |||
346 | static int __init sa1100_mtd_probe(struct device *dev) | 360 | static int __init sa1100_mtd_probe(struct device *dev) |
347 | { | 361 | { |
348 | struct platform_device *pdev = to_platform_device(dev); | 362 | struct platform_device *pdev = to_platform_device(dev); |
349 | struct flash_platform_data *flash = pdev->dev.platform_data; | 363 | struct flash_platform_data *plat = pdev->dev.platform_data; |
350 | struct mtd_partition *parts; | 364 | struct mtd_partition *parts; |
351 | const char *part_type = NULL; | 365 | const char *part_type = NULL; |
352 | struct sa_info *info; | 366 | struct sa_info *info; |
353 | int err, nr_parts = 0; | 367 | int err, nr_parts = 0; |
354 | 368 | ||
355 | if (!flash) | 369 | if (!plat) |
356 | return -ENODEV; | 370 | return -ENODEV; |
357 | 371 | ||
358 | info = sa1100_setup_mtd(pdev, flash); | 372 | info = sa1100_setup_mtd(pdev, plat); |
359 | if (IS_ERR(info)) { | 373 | if (IS_ERR(info)) { |
360 | err = PTR_ERR(info); | 374 | err = PTR_ERR(info); |
361 | goto out; | 375 | goto out; |
@@ -372,8 +386,8 @@ static int __init sa1100_mtd_probe(struct device *dev) | |||
372 | } else | 386 | } else |
373 | #endif | 387 | #endif |
374 | { | 388 | { |
375 | parts = flash->parts; | 389 | parts = plat->parts; |
376 | nr_parts = flash->nr_parts; | 390 | nr_parts = plat->nr_parts; |
377 | part_type = "static"; | 391 | part_type = "static"; |
378 | } | 392 | } |
379 | 393 | ||
@@ -387,6 +401,8 @@ static int __init sa1100_mtd_probe(struct device *dev) | |||
387 | add_mtd_partitions(info->mtd, parts, nr_parts); | 401 | add_mtd_partitions(info->mtd, parts, nr_parts); |
388 | } | 402 | } |
389 | 403 | ||
404 | info->nr_parts = nr_parts; | ||
405 | |||
390 | dev_set_drvdata(dev, info); | 406 | dev_set_drvdata(dev, info); |
391 | err = 0; | 407 | err = 0; |
392 | 408 | ||
@@ -397,33 +413,44 @@ static int __init sa1100_mtd_probe(struct device *dev) | |||
397 | static int __exit sa1100_mtd_remove(struct device *dev) | 413 | static int __exit sa1100_mtd_remove(struct device *dev) |
398 | { | 414 | { |
399 | struct sa_info *info = dev_get_drvdata(dev); | 415 | struct sa_info *info = dev_get_drvdata(dev); |
416 | struct flash_platform_data *plat = dev->platform_data; | ||
417 | |||
400 | dev_set_drvdata(dev, NULL); | 418 | dev_set_drvdata(dev, NULL); |
401 | sa1100_destroy(info); | 419 | sa1100_destroy(info, plat); |
420 | |||
402 | return 0; | 421 | return 0; |
403 | } | 422 | } |
404 | 423 | ||
405 | #ifdef CONFIG_PM | 424 | #ifdef CONFIG_PM |
406 | static int sa1100_mtd_suspend(struct device *dev, pm_message_t state, u32 level) | 425 | static int sa1100_mtd_suspend(struct device *dev, pm_message_t state) |
407 | { | 426 | { |
408 | struct sa_info *info = dev_get_drvdata(dev); | 427 | struct sa_info *info = dev_get_drvdata(dev); |
409 | int ret = 0; | 428 | int ret = 0; |
410 | 429 | ||
411 | if (info && level == SUSPEND_SAVE_STATE) | 430 | if (info) |
412 | ret = info->mtd->suspend(info->mtd); | 431 | ret = info->mtd->suspend(info->mtd); |
413 | 432 | ||
414 | return ret; | 433 | return ret; |
415 | } | 434 | } |
416 | 435 | ||
417 | static int sa1100_mtd_resume(struct device *dev, u32 level) | 436 | static int sa1100_mtd_resume(struct device *dev) |
418 | { | 437 | { |
419 | struct sa_info *info = dev_get_drvdata(dev); | 438 | struct sa_info *info = dev_get_drvdata(dev); |
420 | if (info && level == RESUME_RESTORE_STATE) | 439 | if (info) |
421 | info->mtd->resume(info->mtd); | 440 | info->mtd->resume(info->mtd); |
422 | return 0; | 441 | return 0; |
423 | } | 442 | } |
443 | |||
444 | static void sa1100_mtd_shutdown(struct device *dev) | ||
445 | { | ||
446 | struct sa_info *info = dev_get_drvdata(dev); | ||
447 | if (info && info->mtd->suspend(info->mtd) == 0) | ||
448 | info->mtd->resume(info->mtd); | ||
449 | } | ||
424 | #else | 450 | #else |
425 | #define sa1100_mtd_suspend NULL | 451 | #define sa1100_mtd_suspend NULL |
426 | #define sa1100_mtd_resume NULL | 452 | #define sa1100_mtd_resume NULL |
453 | #define sa1100_mtd_shutdown NULL | ||
427 | #endif | 454 | #endif |
428 | 455 | ||
429 | static struct device_driver sa1100_mtd_driver = { | 456 | static struct device_driver sa1100_mtd_driver = { |
@@ -433,6 +460,7 @@ static struct device_driver sa1100_mtd_driver = { | |||
433 | .remove = __exit_p(sa1100_mtd_remove), | 460 | .remove = __exit_p(sa1100_mtd_remove), |
434 | .suspend = sa1100_mtd_suspend, | 461 | .suspend = sa1100_mtd_suspend, |
435 | .resume = sa1100_mtd_resume, | 462 | .resume = sa1100_mtd_resume, |
463 | .shutdown = sa1100_mtd_shutdown, | ||
436 | }; | 464 | }; |
437 | 465 | ||
438 | static int __init sa1100_mtd_init(void) | 466 | static int __init sa1100_mtd_init(void) |