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 13afffeec9SArtem Bityutskiy static const char * const 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 47f1a7c9d3SRafał Miłecki /************************************************** 48f1a7c9d3SRafał Miłecki * BCMA 49f1a7c9d3SRafał Miłecki **************************************************/ 50f1a7c9d3SRafał Miłecki 51*265dfbd9SRafał Miłecki static int bcm47xxsflash_bcma_cc_read(struct bcm47xxsflash *b47s, u16 offset) 52*265dfbd9SRafał Miłecki { 53*265dfbd9SRafał Miłecki return bcma_cc_read32(b47s->bcma_cc, offset); 54*265dfbd9SRafał Miłecki } 55*265dfbd9SRafał Miłecki 56*265dfbd9SRafał Miłecki static void bcm47xxsflash_bcma_cc_write(struct bcm47xxsflash *b47s, u16 offset, 57*265dfbd9SRafał Miłecki u32 value) 58*265dfbd9SRafał Miłecki { 59*265dfbd9SRafał Miłecki bcma_cc_write32(b47s->bcma_cc, offset, value); 60*265dfbd9SRafał Miłecki } 61*265dfbd9SRafał Miłecki 62f1a7c9d3SRafał Miłecki static int bcm47xxsflash_bcma_probe(struct platform_device *pdev) 635fe42d5bSRafał Miłecki { 645fe42d5bSRafał Miłecki struct bcma_sflash *sflash = dev_get_platdata(&pdev->dev); 65a2f74a7dSRafał Miłecki struct bcm47xxsflash *b47s; 665fe42d5bSRafał Miłecki int err; 675fe42d5bSRafał Miłecki 68a2f74a7dSRafał Miłecki b47s = kzalloc(sizeof(*b47s), GFP_KERNEL); 69a2f74a7dSRafał Miłecki if (!b47s) { 705fe42d5bSRafał Miłecki err = -ENOMEM; 715fe42d5bSRafał Miłecki goto out; 725fe42d5bSRafał Miłecki } 73a2f74a7dSRafał Miłecki sflash->priv = b47s; 745fe42d5bSRafał Miłecki 7541c81536SRafał Miłecki b47s->bcma_cc = container_of(sflash, struct bcma_drv_cc, sflash); 76*265dfbd9SRafał Miłecki b47s->cc_read = bcm47xxsflash_bcma_cc_read; 77*265dfbd9SRafał Miłecki b47s->cc_write = bcm47xxsflash_bcma_cc_write; 7841c81536SRafał Miłecki 791f816bc7SRafał Miłecki switch (b47s->bcma_cc->capabilities & BCMA_CC_CAP_FLASHT) { 801f816bc7SRafał Miłecki case BCMA_CC_FLASHT_STSER: 811f816bc7SRafał Miłecki b47s->type = BCM47XXSFLASH_TYPE_ST; 821f816bc7SRafał Miłecki break; 831f816bc7SRafał Miłecki case BCMA_CC_FLASHT_ATSER: 841f816bc7SRafał Miłecki b47s->type = BCM47XXSFLASH_TYPE_ATMEL; 851f816bc7SRafał Miłecki break; 861f816bc7SRafał Miłecki } 871f816bc7SRafał Miłecki 88a2f74a7dSRafał Miłecki b47s->window = sflash->window; 89a2f74a7dSRafał Miłecki b47s->blocksize = sflash->blocksize; 90a2f74a7dSRafał Miłecki b47s->numblocks = sflash->numblocks; 91a2f74a7dSRafał Miłecki b47s->size = sflash->size; 92a2f74a7dSRafał Miłecki bcm47xxsflash_fill_mtd(b47s); 93a2f74a7dSRafał Miłecki 94a2f74a7dSRafał Miłecki err = mtd_device_parse_register(&b47s->mtd, probes, NULL, NULL, 0); 955fe42d5bSRafał Miłecki if (err) { 965fe42d5bSRafał Miłecki pr_err("Failed to register MTD device: %d\n", err); 975fe42d5bSRafał Miłecki goto err_dev_reg; 985fe42d5bSRafał Miłecki } 995fe42d5bSRafał Miłecki 1005fe42d5bSRafał Miłecki return 0; 1015fe42d5bSRafał Miłecki 1025fe42d5bSRafał Miłecki err_dev_reg: 103a2f74a7dSRafał Miłecki kfree(&b47s->mtd); 1045fe42d5bSRafał Miłecki out: 1055fe42d5bSRafał Miłecki return err; 1065fe42d5bSRafał Miłecki } 1075fe42d5bSRafał Miłecki 108f1a7c9d3SRafał Miłecki static int bcm47xxsflash_bcma_remove(struct platform_device *pdev) 1095fe42d5bSRafał Miłecki { 1105fe42d5bSRafał Miłecki struct bcma_sflash *sflash = dev_get_platdata(&pdev->dev); 111a2f74a7dSRafał Miłecki struct bcm47xxsflash *b47s = sflash->priv; 1125fe42d5bSRafał Miłecki 113a2f74a7dSRafał Miłecki mtd_device_unregister(&b47s->mtd); 114a2f74a7dSRafał Miłecki kfree(b47s); 1155fe42d5bSRafał Miłecki 1165fe42d5bSRafał Miłecki return 0; 1175fe42d5bSRafał Miłecki } 1185fe42d5bSRafał Miłecki 1195fe42d5bSRafał Miłecki static struct platform_driver bcma_sflash_driver = { 120f1a7c9d3SRafał Miłecki .probe = bcm47xxsflash_bcma_probe, 121f1a7c9d3SRafał Miłecki .remove = bcm47xxsflash_bcma_remove, 1225fe42d5bSRafał Miłecki .driver = { 1235fe42d5bSRafał Miłecki .name = "bcma_sflash", 1245fe42d5bSRafał Miłecki .owner = THIS_MODULE, 1255fe42d5bSRafał Miłecki }, 1265fe42d5bSRafał Miłecki }; 1275fe42d5bSRafał Miłecki 128f1a7c9d3SRafał Miłecki /************************************************** 129f1a7c9d3SRafał Miłecki * Init 130f1a7c9d3SRafał Miłecki **************************************************/ 131f1a7c9d3SRafał Miłecki 1325fe42d5bSRafał Miłecki static int __init bcm47xxsflash_init(void) 1335fe42d5bSRafał Miłecki { 1345fe42d5bSRafał Miłecki int err; 1355fe42d5bSRafał Miłecki 1362d13dc3bSHauke Mehrtens err = platform_driver_register(&bcma_sflash_driver); 1375fe42d5bSRafał Miłecki if (err) 1385fe42d5bSRafał Miłecki pr_err("Failed to register BCMA serial flash driver: %d\n", 1395fe42d5bSRafał Miłecki err); 1405fe42d5bSRafał Miłecki 1415fe42d5bSRafał Miłecki return err; 1425fe42d5bSRafał Miłecki } 1435fe42d5bSRafał Miłecki 1445fe42d5bSRafał Miłecki static void __exit bcm47xxsflash_exit(void) 1455fe42d5bSRafał Miłecki { 1465fe42d5bSRafał Miłecki platform_driver_unregister(&bcma_sflash_driver); 1475fe42d5bSRafał Miłecki } 1485fe42d5bSRafał Miłecki 1495fe42d5bSRafał Miłecki module_init(bcm47xxsflash_init); 1505fe42d5bSRafał Miłecki module_exit(bcm47xxsflash_exit); 151