blob: fa56a47a598da22f8bd7d297981dc6dad8a74689 [file] [log] [blame]
Rafał Miłecki5fe42d52012-09-17 11:50:49 +02001#include <linux/kernel.h>
2#include <linux/module.h>
3#include <linux/slab.h>
Rafał Miłeckibddcb5e2013-03-24 21:51:31 +01004#include <linux/delay.h>
Rafał Miłecki5fe42d52012-09-17 11:50:49 +02005#include <linux/mtd/mtd.h>
6#include <linux/platform_device.h>
7#include <linux/bcma/bcma.h>
8
Rafał Miłeckia2f74a72013-01-06 21:28:50 +01009#include "bcm47xxsflash.h"
10
Rafał Miłecki5fe42d52012-09-17 11:50:49 +020011MODULE_LICENSE("GPL");
12MODULE_DESCRIPTION("Serial flash driver for BCMA bus");
13
Artem Bityutskiyafffeec2013-03-12 10:50:07 +020014static const char * const probes[] = { "bcm47xxpart", NULL };
Rafał Miłecki5fe42d52012-09-17 11:50:49 +020015
Rafał Miłeckibddcb5e2013-03-24 21:51:31 +010016/**************************************************
17 * Various helpers
18 **************************************************/
19
20static void bcm47xxsflash_cmd(struct bcm47xxsflash *b47s, u32 opcode)
21{
22 int i;
23
24 b47s->cc_write(b47s, BCMA_CC_FLASHCTL, BCMA_CC_FLASHCTL_START | opcode);
25 for (i = 0; i < 1000; i++) {
26 if (!(b47s->cc_read(b47s, BCMA_CC_FLASHCTL) &
27 BCMA_CC_FLASHCTL_BUSY))
28 return;
29 cpu_relax();
30 }
31 pr_err("Control command failed (timeout)!\n");
32}
33
34static int bcm47xxsflash_poll(struct bcm47xxsflash *b47s, int timeout)
35{
36 unsigned long deadline = jiffies + timeout;
37
38 do {
39 switch (b47s->type) {
40 case BCM47XXSFLASH_TYPE_ST:
41 bcm47xxsflash_cmd(b47s, OPCODE_ST_RDSR);
42 if (!(b47s->cc_read(b47s, BCMA_CC_FLASHDATA) &
43 SR_ST_WIP))
44 return 0;
45 break;
46 case BCM47XXSFLASH_TYPE_ATMEL:
47 bcm47xxsflash_cmd(b47s, OPCODE_AT_STATUS);
48 if (b47s->cc_read(b47s, BCMA_CC_FLASHDATA) &
49 SR_AT_READY)
50 return 0;
51 break;
52 }
53
54 cpu_relax();
55 udelay(1);
56 } while (!time_after_eq(jiffies, deadline));
57
58 pr_err("Timeout waiting for flash to be ready!\n");
59
60 return -EBUSY;
61}
62
63/**************************************************
64 * MTD ops
65 **************************************************/
66
Rafał Miłecki5fe42d52012-09-17 11:50:49 +020067static int bcm47xxsflash_read(struct mtd_info *mtd, loff_t from, size_t len,
68 size_t *retlen, u_char *buf)
69{
Rafał Miłeckia2f74a72013-01-06 21:28:50 +010070 struct bcm47xxsflash *b47s = mtd->priv;
Rafał Miłecki5fe42d52012-09-17 11:50:49 +020071
72 /* Check address range */
73 if ((from + len) > mtd->size)
74 return -EINVAL;
75
Rafał Miłeckia2f74a72013-01-06 21:28:50 +010076 memcpy_fromio(buf, (void __iomem *)KSEG0ADDR(b47s->window + from),
Rafał Miłecki5fe42d52012-09-17 11:50:49 +020077 len);
Hauke Mehrtens60aca062013-01-24 17:39:54 +010078 *retlen = len;
Rafał Miłecki5fe42d52012-09-17 11:50:49 +020079
80 return len;
81}
82
Rafał Miłeckia2f74a72013-01-06 21:28:50 +010083static void bcm47xxsflash_fill_mtd(struct bcm47xxsflash *b47s)
Rafał Miłecki5fe42d52012-09-17 11:50:49 +020084{
Rafał Miłeckia2f74a72013-01-06 21:28:50 +010085 struct mtd_info *mtd = &b47s->mtd;
86
87 mtd->priv = b47s;
Rafał Miłecki5fe42d52012-09-17 11:50:49 +020088 mtd->name = "bcm47xxsflash";
89 mtd->owner = THIS_MODULE;
90 mtd->type = MTD_ROM;
Rafał Miłeckia2f74a72013-01-06 21:28:50 +010091 mtd->size = b47s->size;
Rafał Miłecki5fe42d52012-09-17 11:50:49 +020092 mtd->_read = bcm47xxsflash_read;
93
94 /* TODO: implement writing support and verify/change following code */
95 mtd->flags = MTD_CAP_ROM;
96 mtd->writebufsize = mtd->writesize = 1;
97}
98
Rafał Miłeckif1a7c9d2013-02-04 08:23:08 +010099/**************************************************
100 * BCMA
101 **************************************************/
102
Rafał Miłecki265dfbd2013-03-24 21:53:24 +0100103static int bcm47xxsflash_bcma_cc_read(struct bcm47xxsflash *b47s, u16 offset)
104{
105 return bcma_cc_read32(b47s->bcma_cc, offset);
106}
107
108static void bcm47xxsflash_bcma_cc_write(struct bcm47xxsflash *b47s, u16 offset,
109 u32 value)
110{
111 bcma_cc_write32(b47s->bcma_cc, offset, value);
112}
113
Rafał Miłeckif1a7c9d2013-02-04 08:23:08 +0100114static int bcm47xxsflash_bcma_probe(struct platform_device *pdev)
Rafał Miłecki5fe42d52012-09-17 11:50:49 +0200115{
116 struct bcma_sflash *sflash = dev_get_platdata(&pdev->dev);
Rafał Miłeckia2f74a72013-01-06 21:28:50 +0100117 struct bcm47xxsflash *b47s;
Rafał Miłecki5fe42d52012-09-17 11:50:49 +0200118 int err;
119
Libo Chend2b1bd12013-05-30 10:22:12 +0800120 b47s = devm_kzalloc(&pdev->dev, sizeof(*b47s), GFP_KERNEL);
121 if (!b47s)
122 return -ENOMEM;
Rafał Miłeckia2f74a72013-01-06 21:28:50 +0100123 sflash->priv = b47s;
Rafał Miłecki5fe42d52012-09-17 11:50:49 +0200124
Rafał Miłecki41c81532013-03-06 12:33:17 +0100125 b47s->bcma_cc = container_of(sflash, struct bcma_drv_cc, sflash);
Rafał Miłecki265dfbd2013-03-24 21:53:24 +0100126 b47s->cc_read = bcm47xxsflash_bcma_cc_read;
127 b47s->cc_write = bcm47xxsflash_bcma_cc_write;
Rafał Miłecki41c81532013-03-06 12:33:17 +0100128
Rafał Miłecki1f816bc2013-03-06 12:34:19 +0100129 switch (b47s->bcma_cc->capabilities & BCMA_CC_CAP_FLASHT) {
130 case BCMA_CC_FLASHT_STSER:
131 b47s->type = BCM47XXSFLASH_TYPE_ST;
132 break;
133 case BCMA_CC_FLASHT_ATSER:
134 b47s->type = BCM47XXSFLASH_TYPE_ATMEL;
135 break;
136 }
137
Rafał Miłeckia2f74a72013-01-06 21:28:50 +0100138 b47s->window = sflash->window;
139 b47s->blocksize = sflash->blocksize;
140 b47s->numblocks = sflash->numblocks;
141 b47s->size = sflash->size;
142 bcm47xxsflash_fill_mtd(b47s);
143
144 err = mtd_device_parse_register(&b47s->mtd, probes, NULL, NULL, 0);
Rafał Miłecki5fe42d52012-09-17 11:50:49 +0200145 if (err) {
146 pr_err("Failed to register MTD device: %d\n", err);
Libo Chend2b1bd12013-05-30 10:22:12 +0800147 return err;
Rafał Miłecki5fe42d52012-09-17 11:50:49 +0200148 }
149
Rafał Miłeckibddcb5e2013-03-24 21:51:31 +0100150 if (bcm47xxsflash_poll(b47s, HZ / 10))
151 pr_warn("Serial flash busy\n");
152
Rafał Miłecki5fe42d52012-09-17 11:50:49 +0200153 return 0;
Rafał Miłecki5fe42d52012-09-17 11:50:49 +0200154}
155
Rafał Miłeckif1a7c9d2013-02-04 08:23:08 +0100156static int bcm47xxsflash_bcma_remove(struct platform_device *pdev)
Rafał Miłecki5fe42d52012-09-17 11:50:49 +0200157{
158 struct bcma_sflash *sflash = dev_get_platdata(&pdev->dev);
Rafał Miłeckia2f74a72013-01-06 21:28:50 +0100159 struct bcm47xxsflash *b47s = sflash->priv;
Rafał Miłecki5fe42d52012-09-17 11:50:49 +0200160
Rafał Miłeckia2f74a72013-01-06 21:28:50 +0100161 mtd_device_unregister(&b47s->mtd);
Rafał Miłecki5fe42d52012-09-17 11:50:49 +0200162
163 return 0;
164}
165
166static struct platform_driver bcma_sflash_driver = {
Rafał Miłeckif1a7c9d2013-02-04 08:23:08 +0100167 .probe = bcm47xxsflash_bcma_probe,
168 .remove = bcm47xxsflash_bcma_remove,
Rafał Miłecki5fe42d52012-09-17 11:50:49 +0200169 .driver = {
170 .name = "bcma_sflash",
171 .owner = THIS_MODULE,
172 },
173};
174
Rafał Miłeckif1a7c9d2013-02-04 08:23:08 +0100175/**************************************************
176 * Init
177 **************************************************/
178
Rafał Miłecki5fe42d52012-09-17 11:50:49 +0200179static int __init bcm47xxsflash_init(void)
180{
181 int err;
182
Hauke Mehrtens2d13dc32013-01-24 17:39:55 +0100183 err = platform_driver_register(&bcma_sflash_driver);
Rafał Miłecki5fe42d52012-09-17 11:50:49 +0200184 if (err)
185 pr_err("Failed to register BCMA serial flash driver: %d\n",
186 err);
187
188 return err;
189}
190
191static void __exit bcm47xxsflash_exit(void)
192{
193 platform_driver_unregister(&bcma_sflash_driver);
194}
195
196module_init(bcm47xxsflash_init);
197module_exit(bcm47xxsflash_exit);