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 8a2f74a7dSRafał Miłecki #include "bcm47xxsflash.h" 9a2f74a7dSRafał 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 { 18a2f74a7dSRafał 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 24a2f74a7dSRafał Miłecki memcpy_fromio(buf, (void __iomem *)KSEG0ADDR(b47s->window + from), 255fe42d5bSRafał Miłecki len); 2660aca067SHauke Mehrtens *retlen = len; 275fe42d5bSRafał Miłecki 285fe42d5bSRafał Miłecki return len; 295fe42d5bSRafał Miłecki } 305fe42d5bSRafał Miłecki 31a2f74a7dSRafał Miłecki static void bcm47xxsflash_fill_mtd(struct bcm47xxsflash *b47s) 325fe42d5bSRafał Miłecki { 33a2f74a7dSRafał Miłecki struct mtd_info *mtd = &b47s->mtd; 34a2f74a7dSRafał Miłecki 35a2f74a7dSRafał Miłecki mtd->priv = b47s; 365fe42d5bSRafał Miłecki mtd->name = "bcm47xxsflash"; 375fe42d5bSRafał Miłecki mtd->owner = THIS_MODULE; 385fe42d5bSRafał Miłecki mtd->type = MTD_ROM; 39a2f74a7dSRafał Miłecki mtd->size = b47s->size; 405fe42d5bSRafał Miłecki mtd->_read = bcm47xxsflash_read; 415fe42d5bSRafał Miłecki 425fe42d5bSRafał Miłecki /* TODO: implement writing support and verify/change following code */ 435fe42d5bSRafał Miłecki mtd->flags = MTD_CAP_ROM; 445fe42d5bSRafał Miłecki mtd->writebufsize = mtd->writesize = 1; 455fe42d5bSRafał Miłecki } 465fe42d5bSRafał Miłecki 47*f1a7c9d3SRafał Miłecki /************************************************** 48*f1a7c9d3SRafał Miłecki * BCMA 49*f1a7c9d3SRafał Miłecki **************************************************/ 50*f1a7c9d3SRafał Miłecki 51*f1a7c9d3SRafał Miłecki static int bcm47xxsflash_bcma_probe(struct platform_device *pdev) 525fe42d5bSRafał Miłecki { 535fe42d5bSRafał Miłecki struct bcma_sflash *sflash = dev_get_platdata(&pdev->dev); 54a2f74a7dSRafał Miłecki struct bcm47xxsflash *b47s; 555fe42d5bSRafał Miłecki int err; 565fe42d5bSRafał Miłecki 57a2f74a7dSRafał Miłecki b47s = kzalloc(sizeof(*b47s), GFP_KERNEL); 58a2f74a7dSRafał Miłecki if (!b47s) { 595fe42d5bSRafał Miłecki err = -ENOMEM; 605fe42d5bSRafał Miłecki goto out; 615fe42d5bSRafał Miłecki } 62a2f74a7dSRafał Miłecki sflash->priv = b47s; 635fe42d5bSRafał Miłecki 64a2f74a7dSRafał Miłecki b47s->window = sflash->window; 65a2f74a7dSRafał Miłecki b47s->blocksize = sflash->blocksize; 66a2f74a7dSRafał Miłecki b47s->numblocks = sflash->numblocks; 67a2f74a7dSRafał Miłecki b47s->size = sflash->size; 68a2f74a7dSRafał Miłecki bcm47xxsflash_fill_mtd(b47s); 69a2f74a7dSRafał Miłecki 70a2f74a7dSRafał Miłecki err = mtd_device_parse_register(&b47s->mtd, probes, NULL, NULL, 0); 715fe42d5bSRafał Miłecki if (err) { 725fe42d5bSRafał Miłecki pr_err("Failed to register MTD device: %d\n", err); 735fe42d5bSRafał Miłecki goto err_dev_reg; 745fe42d5bSRafał Miłecki } 755fe42d5bSRafał Miłecki 765fe42d5bSRafał Miłecki return 0; 775fe42d5bSRafał Miłecki 785fe42d5bSRafał Miłecki err_dev_reg: 79a2f74a7dSRafał Miłecki kfree(&b47s->mtd); 805fe42d5bSRafał Miłecki out: 815fe42d5bSRafał Miłecki return err; 825fe42d5bSRafał Miłecki } 835fe42d5bSRafał Miłecki 84*f1a7c9d3SRafał Miłecki static int bcm47xxsflash_bcma_remove(struct platform_device *pdev) 855fe42d5bSRafał Miłecki { 865fe42d5bSRafał Miłecki struct bcma_sflash *sflash = dev_get_platdata(&pdev->dev); 87a2f74a7dSRafał Miłecki struct bcm47xxsflash *b47s = sflash->priv; 885fe42d5bSRafał Miłecki 89a2f74a7dSRafał Miłecki mtd_device_unregister(&b47s->mtd); 90a2f74a7dSRafał Miłecki kfree(b47s); 915fe42d5bSRafał Miłecki 925fe42d5bSRafał Miłecki return 0; 935fe42d5bSRafał Miłecki } 945fe42d5bSRafał Miłecki 955fe42d5bSRafał Miłecki static struct platform_driver bcma_sflash_driver = { 96*f1a7c9d3SRafał Miłecki .probe = bcm47xxsflash_bcma_probe, 97*f1a7c9d3SRafał Miłecki .remove = bcm47xxsflash_bcma_remove, 985fe42d5bSRafał Miłecki .driver = { 995fe42d5bSRafał Miłecki .name = "bcma_sflash", 1005fe42d5bSRafał Miłecki .owner = THIS_MODULE, 1015fe42d5bSRafał Miłecki }, 1025fe42d5bSRafał Miłecki }; 1035fe42d5bSRafał Miłecki 104*f1a7c9d3SRafał Miłecki /************************************************** 105*f1a7c9d3SRafał Miłecki * Init 106*f1a7c9d3SRafał Miłecki **************************************************/ 107*f1a7c9d3SRafał Miłecki 1085fe42d5bSRafał Miłecki static int __init bcm47xxsflash_init(void) 1095fe42d5bSRafał Miłecki { 1105fe42d5bSRafał Miłecki int err; 1115fe42d5bSRafał Miłecki 1122d13dc3bSHauke Mehrtens err = platform_driver_register(&bcma_sflash_driver); 1135fe42d5bSRafał Miłecki if (err) 1145fe42d5bSRafał Miłecki pr_err("Failed to register BCMA serial flash driver: %d\n", 1155fe42d5bSRafał Miłecki err); 1165fe42d5bSRafał Miłecki 1175fe42d5bSRafał Miłecki return err; 1185fe42d5bSRafał Miłecki } 1195fe42d5bSRafał Miłecki 1205fe42d5bSRafał Miłecki static void __exit bcm47xxsflash_exit(void) 1215fe42d5bSRafał Miłecki { 1225fe42d5bSRafał Miłecki platform_driver_unregister(&bcma_sflash_driver); 1235fe42d5bSRafał Miłecki } 1245fe42d5bSRafał Miłecki 1255fe42d5bSRafał Miłecki module_init(bcm47xxsflash_init); 1265fe42d5bSRafał Miłecki module_exit(bcm47xxsflash_exit); 127