15fe42d5bSRafał Miłecki #include <linux/kernel.h> 25fe42d5bSRafał Miłecki #include <linux/module.h> 35fe42d5bSRafał Miłecki #include <linux/slab.h> 45fe42d5bSRafał Miłecki #include <linux/mtd/mtd.h> 55fe42d5bSRafał Miłecki #include <linux/platform_device.h> 65fe42d5bSRafał Miłecki #include <linux/bcma/bcma.h> 75fe42d5bSRafał Miłecki 8*a2f74a7dSRafał Miłecki #include "bcm47xxsflash.h" 9*a2f74a7dSRafał Miłecki 105fe42d5bSRafał Miłecki MODULE_LICENSE("GPL"); 115fe42d5bSRafał Miłecki MODULE_DESCRIPTION("Serial flash driver for BCMA bus"); 125fe42d5bSRafał Miłecki 135fe42d5bSRafał Miłecki static const char *probes[] = { "bcm47xxpart", NULL }; 145fe42d5bSRafał Miłecki 155fe42d5bSRafał Miłecki static int bcm47xxsflash_read(struct mtd_info *mtd, loff_t from, size_t len, 165fe42d5bSRafał Miłecki size_t *retlen, u_char *buf) 175fe42d5bSRafał Miłecki { 18*a2f74a7dSRafał Miłecki struct bcm47xxsflash *b47s = mtd->priv; 195fe42d5bSRafał Miłecki 205fe42d5bSRafał Miłecki /* Check address range */ 215fe42d5bSRafał Miłecki if ((from + len) > mtd->size) 225fe42d5bSRafał Miłecki return -EINVAL; 235fe42d5bSRafał Miłecki 24*a2f74a7dSRafał Miłecki memcpy_fromio(buf, (void __iomem *)KSEG0ADDR(b47s->window + from), 255fe42d5bSRafał Miłecki len); 265fe42d5bSRafał Miłecki 275fe42d5bSRafał Miłecki return len; 285fe42d5bSRafał Miłecki } 295fe42d5bSRafał Miłecki 30*a2f74a7dSRafał Miłecki static void bcm47xxsflash_fill_mtd(struct bcm47xxsflash *b47s) 315fe42d5bSRafał Miłecki { 32*a2f74a7dSRafał Miłecki struct mtd_info *mtd = &b47s->mtd; 33*a2f74a7dSRafał Miłecki 34*a2f74a7dSRafał Miłecki mtd->priv = b47s; 355fe42d5bSRafał Miłecki mtd->name = "bcm47xxsflash"; 365fe42d5bSRafał Miłecki mtd->owner = THIS_MODULE; 375fe42d5bSRafał Miłecki mtd->type = MTD_ROM; 38*a2f74a7dSRafał Miłecki mtd->size = b47s->size; 395fe42d5bSRafał Miłecki mtd->_read = bcm47xxsflash_read; 405fe42d5bSRafał Miłecki 415fe42d5bSRafał Miłecki /* TODO: implement writing support and verify/change following code */ 425fe42d5bSRafał Miłecki mtd->flags = MTD_CAP_ROM; 435fe42d5bSRafał Miłecki mtd->writebufsize = mtd->writesize = 1; 445fe42d5bSRafał Miłecki } 455fe42d5bSRafał Miłecki 465fe42d5bSRafał Miłecki static int bcm47xxsflash_probe(struct platform_device *pdev) 475fe42d5bSRafał Miłecki { 485fe42d5bSRafał Miłecki struct bcma_sflash *sflash = dev_get_platdata(&pdev->dev); 49*a2f74a7dSRafał Miłecki struct bcm47xxsflash *b47s; 505fe42d5bSRafał Miłecki int err; 515fe42d5bSRafał Miłecki 52*a2f74a7dSRafał Miłecki b47s = kzalloc(sizeof(*b47s), GFP_KERNEL); 53*a2f74a7dSRafał Miłecki if (!b47s) { 545fe42d5bSRafał Miłecki err = -ENOMEM; 555fe42d5bSRafał Miłecki goto out; 565fe42d5bSRafał Miłecki } 57*a2f74a7dSRafał Miłecki sflash->priv = b47s; 585fe42d5bSRafał Miłecki 59*a2f74a7dSRafał Miłecki b47s->window = sflash->window; 60*a2f74a7dSRafał Miłecki b47s->blocksize = sflash->blocksize; 61*a2f74a7dSRafał Miłecki b47s->numblocks = sflash->numblocks; 62*a2f74a7dSRafał Miłecki b47s->size = sflash->size; 63*a2f74a7dSRafał Miłecki bcm47xxsflash_fill_mtd(b47s); 64*a2f74a7dSRafał Miłecki 65*a2f74a7dSRafał Miłecki err = mtd_device_parse_register(&b47s->mtd, probes, NULL, NULL, 0); 665fe42d5bSRafał Miłecki if (err) { 675fe42d5bSRafał Miłecki pr_err("Failed to register MTD device: %d\n", err); 685fe42d5bSRafał Miłecki goto err_dev_reg; 695fe42d5bSRafał Miłecki } 705fe42d5bSRafał Miłecki 715fe42d5bSRafał Miłecki return 0; 725fe42d5bSRafał Miłecki 735fe42d5bSRafał Miłecki err_dev_reg: 74*a2f74a7dSRafał Miłecki kfree(&b47s->mtd); 755fe42d5bSRafał Miłecki out: 765fe42d5bSRafał Miłecki return err; 775fe42d5bSRafał Miłecki } 785fe42d5bSRafał Miłecki 79810b7e06SBill Pemberton static int bcm47xxsflash_remove(struct platform_device *pdev) 805fe42d5bSRafał Miłecki { 815fe42d5bSRafał Miłecki struct bcma_sflash *sflash = dev_get_platdata(&pdev->dev); 82*a2f74a7dSRafał Miłecki struct bcm47xxsflash *b47s = sflash->priv; 835fe42d5bSRafał Miłecki 84*a2f74a7dSRafał Miłecki mtd_device_unregister(&b47s->mtd); 85*a2f74a7dSRafał Miłecki kfree(b47s); 865fe42d5bSRafał Miłecki 875fe42d5bSRafał Miłecki return 0; 885fe42d5bSRafał Miłecki } 895fe42d5bSRafał Miłecki 905fe42d5bSRafał Miłecki static struct platform_driver bcma_sflash_driver = { 915153b88cSBill Pemberton .remove = bcm47xxsflash_remove, 925fe42d5bSRafał Miłecki .driver = { 935fe42d5bSRafał Miłecki .name = "bcma_sflash", 945fe42d5bSRafał Miłecki .owner = THIS_MODULE, 955fe42d5bSRafał Miłecki }, 965fe42d5bSRafał Miłecki }; 975fe42d5bSRafał Miłecki 985fe42d5bSRafał Miłecki static int __init bcm47xxsflash_init(void) 995fe42d5bSRafał Miłecki { 1005fe42d5bSRafał Miłecki int err; 1015fe42d5bSRafał Miłecki 1025fe42d5bSRafał Miłecki err = platform_driver_probe(&bcma_sflash_driver, bcm47xxsflash_probe); 1035fe42d5bSRafał Miłecki if (err) 1045fe42d5bSRafał Miłecki pr_err("Failed to register BCMA serial flash driver: %d\n", 1055fe42d5bSRafał Miłecki err); 1065fe42d5bSRafał Miłecki 1075fe42d5bSRafał Miłecki return err; 1085fe42d5bSRafał Miłecki } 1095fe42d5bSRafał Miłecki 1105fe42d5bSRafał Miłecki static void __exit bcm47xxsflash_exit(void) 1115fe42d5bSRafał Miłecki { 1125fe42d5bSRafał Miłecki platform_driver_unregister(&bcma_sflash_driver); 1135fe42d5bSRafał Miłecki } 1145fe42d5bSRafał Miłecki 1155fe42d5bSRafał Miłecki module_init(bcm47xxsflash_init); 1165fe42d5bSRafał Miłecki module_exit(bcm47xxsflash_exit); 117