diff options
Diffstat (limited to 'drivers/mtd/nand/bcm47xxnflash/main.c')
| -rw-r--r-- | drivers/mtd/nand/bcm47xxnflash/main.c | 108 |
1 files changed, 108 insertions, 0 deletions
diff --git a/drivers/mtd/nand/bcm47xxnflash/main.c b/drivers/mtd/nand/bcm47xxnflash/main.c new file mode 100644 index 000000000000..8363a9a5fa3f --- /dev/null +++ b/drivers/mtd/nand/bcm47xxnflash/main.c | |||
| @@ -0,0 +1,108 @@ | |||
| 1 | /* | ||
| 2 | * BCM47XX NAND flash driver | ||
| 3 | * | ||
| 4 | * Copyright (C) 2012 Rafał Miłecki <zajec5@gmail.com> | ||
| 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 | */ | ||
| 11 | |||
| 12 | #include <linux/module.h> | ||
| 13 | #include <linux/kernel.h> | ||
| 14 | #include <linux/slab.h> | ||
| 15 | #include <linux/platform_device.h> | ||
| 16 | #include <linux/bcma/bcma.h> | ||
| 17 | |||
| 18 | #include "bcm47xxnflash.h" | ||
| 19 | |||
| 20 | MODULE_DESCRIPTION("NAND flash driver for BCMA bus"); | ||
| 21 | MODULE_LICENSE("GPL"); | ||
| 22 | MODULE_AUTHOR("Rafał Miłecki"); | ||
| 23 | |||
| 24 | static const char *probes[] = { "bcm47xxpart", NULL }; | ||
| 25 | |||
| 26 | static int bcm47xxnflash_probe(struct platform_device *pdev) | ||
| 27 | { | ||
| 28 | struct bcma_nflash *nflash = dev_get_platdata(&pdev->dev); | ||
| 29 | struct bcm47xxnflash *b47n; | ||
| 30 | int err = 0; | ||
| 31 | |||
| 32 | b47n = kzalloc(sizeof(*b47n), GFP_KERNEL); | ||
| 33 | if (!b47n) { | ||
| 34 | err = -ENOMEM; | ||
| 35 | goto out; | ||
| 36 | } | ||
| 37 | |||
| 38 | b47n->nand_chip.priv = b47n; | ||
| 39 | b47n->mtd.owner = THIS_MODULE; | ||
| 40 | b47n->mtd.priv = &b47n->nand_chip; /* Required */ | ||
| 41 | b47n->cc = container_of(nflash, struct bcma_drv_cc, nflash); | ||
| 42 | |||
| 43 | if (b47n->cc->core->bus->chipinfo.id == BCMA_CHIP_ID_BCM4706) { | ||
| 44 | err = bcm47xxnflash_ops_bcm4706_init(b47n); | ||
| 45 | } else { | ||
| 46 | pr_err("Device not supported\n"); | ||
| 47 | err = -ENOTSUPP; | ||
| 48 | } | ||
| 49 | if (err) { | ||
| 50 | pr_err("Initialization failed: %d\n", err); | ||
| 51 | goto err_init; | ||
| 52 | } | ||
| 53 | |||
| 54 | err = mtd_device_parse_register(&b47n->mtd, probes, NULL, NULL, 0); | ||
| 55 | if (err) { | ||
| 56 | pr_err("Failed to register MTD device: %d\n", err); | ||
| 57 | goto err_dev_reg; | ||
| 58 | } | ||
| 59 | |||
| 60 | return 0; | ||
| 61 | |||
| 62 | err_dev_reg: | ||
| 63 | err_init: | ||
| 64 | kfree(b47n); | ||
| 65 | out: | ||
| 66 | return err; | ||
| 67 | } | ||
| 68 | |||
| 69 | static int bcm47xxnflash_remove(struct platform_device *pdev) | ||
| 70 | { | ||
| 71 | struct bcma_nflash *nflash = dev_get_platdata(&pdev->dev); | ||
| 72 | |||
| 73 | if (nflash->mtd) | ||
| 74 | mtd_device_unregister(nflash->mtd); | ||
| 75 | |||
| 76 | return 0; | ||
| 77 | } | ||
| 78 | |||
| 79 | static struct platform_driver bcm47xxnflash_driver = { | ||
| 80 | .remove = bcm47xxnflash_remove, | ||
| 81 | .driver = { | ||
| 82 | .name = "bcma_nflash", | ||
| 83 | .owner = THIS_MODULE, | ||
| 84 | }, | ||
| 85 | }; | ||
| 86 | |||
| 87 | static int __init bcm47xxnflash_init(void) | ||
| 88 | { | ||
| 89 | int err; | ||
| 90 | |||
| 91 | /* | ||
| 92 | * Platform device "bcma_nflash" exists on SoCs and is registered very | ||
| 93 | * early, it won't be added during runtime (use platform_driver_probe). | ||
| 94 | */ | ||
| 95 | err = platform_driver_probe(&bcm47xxnflash_driver, bcm47xxnflash_probe); | ||
| 96 | if (err) | ||
| 97 | pr_err("Failed to register serial flash driver: %d\n", err); | ||
| 98 | |||
| 99 | return err; | ||
| 100 | } | ||
| 101 | |||
| 102 | static void __exit bcm47xxnflash_exit(void) | ||
| 103 | { | ||
| 104 | platform_driver_unregister(&bcm47xxnflash_driver); | ||
| 105 | } | ||
| 106 | |||
| 107 | module_init(bcm47xxnflash_init); | ||
| 108 | module_exit(bcm47xxnflash_exit); | ||
