xref: /openbmc/linux/drivers/mtd/devices/bcm47xxsflash.c (revision 5fe42d5bf2deac62bf2a532b30deacc007805b91)
1*5fe42d5bSRafał Miłecki #include <linux/kernel.h>
2*5fe42d5bSRafał Miłecki #include <linux/module.h>
3*5fe42d5bSRafał Miłecki #include <linux/slab.h>
4*5fe42d5bSRafał Miłecki #include <linux/mtd/mtd.h>
5*5fe42d5bSRafał Miłecki #include <linux/platform_device.h>
6*5fe42d5bSRafał Miłecki #include <linux/bcma/bcma.h>
7*5fe42d5bSRafał Miłecki 
8*5fe42d5bSRafał Miłecki MODULE_LICENSE("GPL");
9*5fe42d5bSRafał Miłecki MODULE_DESCRIPTION("Serial flash driver for BCMA bus");
10*5fe42d5bSRafał Miłecki 
11*5fe42d5bSRafał Miłecki static const char *probes[] = { "bcm47xxpart", NULL };
12*5fe42d5bSRafał Miłecki 
13*5fe42d5bSRafał Miłecki static int bcm47xxsflash_read(struct mtd_info *mtd, loff_t from, size_t len,
14*5fe42d5bSRafał Miłecki 			      size_t *retlen, u_char *buf)
15*5fe42d5bSRafał Miłecki {
16*5fe42d5bSRafał Miłecki 	struct bcma_sflash *sflash = mtd->priv;
17*5fe42d5bSRafał Miłecki 
18*5fe42d5bSRafał Miłecki 	/* Check address range */
19*5fe42d5bSRafał Miłecki 	if ((from + len) > mtd->size)
20*5fe42d5bSRafał Miłecki 		return -EINVAL;
21*5fe42d5bSRafał Miłecki 
22*5fe42d5bSRafał Miłecki 	memcpy_fromio(buf, (void __iomem *)KSEG0ADDR(sflash->window + from),
23*5fe42d5bSRafał Miłecki 		      len);
24*5fe42d5bSRafał Miłecki 
25*5fe42d5bSRafał Miłecki 	return len;
26*5fe42d5bSRafał Miłecki }
27*5fe42d5bSRafał Miłecki 
28*5fe42d5bSRafał Miłecki static void bcm47xxsflash_fill_mtd(struct bcma_sflash *sflash,
29*5fe42d5bSRafał Miłecki 				   struct mtd_info *mtd)
30*5fe42d5bSRafał Miłecki {
31*5fe42d5bSRafał Miłecki 	mtd->priv = sflash;
32*5fe42d5bSRafał Miłecki 	mtd->name = "bcm47xxsflash";
33*5fe42d5bSRafał Miłecki 	mtd->owner = THIS_MODULE;
34*5fe42d5bSRafał Miłecki 	mtd->type = MTD_ROM;
35*5fe42d5bSRafał Miłecki 	mtd->size = sflash->size;
36*5fe42d5bSRafał Miłecki 	mtd->_read = bcm47xxsflash_read;
37*5fe42d5bSRafał Miłecki 
38*5fe42d5bSRafał Miłecki 	/* TODO: implement writing support and verify/change following code */
39*5fe42d5bSRafał Miłecki 	mtd->flags = MTD_CAP_ROM;
40*5fe42d5bSRafał Miłecki 	mtd->writebufsize = mtd->writesize = 1;
41*5fe42d5bSRafał Miłecki }
42*5fe42d5bSRafał Miłecki 
43*5fe42d5bSRafał Miłecki static int bcm47xxsflash_probe(struct platform_device *pdev)
44*5fe42d5bSRafał Miłecki {
45*5fe42d5bSRafał Miłecki 	struct bcma_sflash *sflash = dev_get_platdata(&pdev->dev);
46*5fe42d5bSRafał Miłecki 	int err;
47*5fe42d5bSRafał Miłecki 
48*5fe42d5bSRafał Miłecki 	sflash->mtd = kzalloc(sizeof(struct mtd_info), GFP_KERNEL);
49*5fe42d5bSRafał Miłecki 	if (!sflash->mtd) {
50*5fe42d5bSRafał Miłecki 		err = -ENOMEM;
51*5fe42d5bSRafał Miłecki 		goto out;
52*5fe42d5bSRafał Miłecki 	}
53*5fe42d5bSRafał Miłecki 	bcm47xxsflash_fill_mtd(sflash, sflash->mtd);
54*5fe42d5bSRafał Miłecki 
55*5fe42d5bSRafał Miłecki 	err = mtd_device_parse_register(sflash->mtd, probes, NULL, NULL, 0);
56*5fe42d5bSRafał Miłecki 	if (err) {
57*5fe42d5bSRafał Miłecki 		pr_err("Failed to register MTD device: %d\n", err);
58*5fe42d5bSRafał Miłecki 		goto err_dev_reg;
59*5fe42d5bSRafał Miłecki 	}
60*5fe42d5bSRafał Miłecki 
61*5fe42d5bSRafał Miłecki 	return 0;
62*5fe42d5bSRafał Miłecki 
63*5fe42d5bSRafał Miłecki err_dev_reg:
64*5fe42d5bSRafał Miłecki 	kfree(sflash->mtd);
65*5fe42d5bSRafał Miłecki out:
66*5fe42d5bSRafał Miłecki 	return err;
67*5fe42d5bSRafał Miłecki }
68*5fe42d5bSRafał Miłecki 
69*5fe42d5bSRafał Miłecki static int __devexit bcm47xxsflash_remove(struct platform_device *pdev)
70*5fe42d5bSRafał Miłecki {
71*5fe42d5bSRafał Miłecki 	struct bcma_sflash *sflash = dev_get_platdata(&pdev->dev);
72*5fe42d5bSRafał Miłecki 
73*5fe42d5bSRafał Miłecki 	mtd_device_unregister(sflash->mtd);
74*5fe42d5bSRafał Miłecki 	kfree(sflash->mtd);
75*5fe42d5bSRafał Miłecki 
76*5fe42d5bSRafał Miłecki 	return 0;
77*5fe42d5bSRafał Miłecki }
78*5fe42d5bSRafał Miłecki 
79*5fe42d5bSRafał Miłecki static struct platform_driver bcma_sflash_driver = {
80*5fe42d5bSRafał Miłecki 	.remove = __devexit_p(bcm47xxsflash_remove),
81*5fe42d5bSRafał Miłecki 	.driver = {
82*5fe42d5bSRafał Miłecki 		.name = "bcma_sflash",
83*5fe42d5bSRafał Miłecki 		.owner = THIS_MODULE,
84*5fe42d5bSRafał Miłecki 	},
85*5fe42d5bSRafał Miłecki };
86*5fe42d5bSRafał Miłecki 
87*5fe42d5bSRafał Miłecki static int __init bcm47xxsflash_init(void)
88*5fe42d5bSRafał Miłecki {
89*5fe42d5bSRafał Miłecki 	int err;
90*5fe42d5bSRafał Miłecki 
91*5fe42d5bSRafał Miłecki 	err = platform_driver_probe(&bcma_sflash_driver, bcm47xxsflash_probe);
92*5fe42d5bSRafał Miłecki 	if (err)
93*5fe42d5bSRafał Miłecki 		pr_err("Failed to register BCMA serial flash driver: %d\n",
94*5fe42d5bSRafał Miłecki 		       err);
95*5fe42d5bSRafał Miłecki 
96*5fe42d5bSRafał Miłecki 	return err;
97*5fe42d5bSRafał Miłecki }
98*5fe42d5bSRafał Miłecki 
99*5fe42d5bSRafał Miłecki static void __exit bcm47xxsflash_exit(void)
100*5fe42d5bSRafał Miłecki {
101*5fe42d5bSRafał Miłecki 	platform_driver_unregister(&bcma_sflash_driver);
102*5fe42d5bSRafał Miłecki }
103*5fe42d5bSRafał Miłecki 
104*5fe42d5bSRafał Miłecki module_init(bcm47xxsflash_init);
105*5fe42d5bSRafał Miłecki module_exit(bcm47xxsflash_exit);
106