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