xref: /openbmc/linux/drivers/mtd/devices/bcm47xxsflash.c (revision a2f74a7dacc1c17a0b146eb3112217874c5db436)
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