]> Pileus Git - ~andy/linux/blob - drivers/mtd/devices/bcm47xxsflash.c
534cb741b107539798863a85d381359e6519f73e
[~andy/linux] / drivers / mtd / devices / bcm47xxsflash.c
1 #include <linux/kernel.h>
2 #include <linux/module.h>
3 #include <linux/slab.h>
4 #include <linux/delay.h>
5 #include <linux/mtd/mtd.h>
6 #include <linux/platform_device.h>
7 #include <linux/bcma/bcma.h>
8
9 #include "bcm47xxsflash.h"
10
11 MODULE_LICENSE("GPL");
12 MODULE_DESCRIPTION("Serial flash driver for BCMA bus");
13
14 static const char * const probes[] = { "bcm47xxpart", NULL };
15
16 /**************************************************
17  * Various helpers
18  **************************************************/
19
20 static 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
34 static 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
67 static int bcm47xxsflash_erase(struct mtd_info *mtd, struct erase_info *erase)
68 {
69         struct bcm47xxsflash *b47s = mtd->priv;
70         int err;
71
72         switch (b47s->type) {
73         case BCM47XXSFLASH_TYPE_ST:
74                 bcm47xxsflash_cmd(b47s, OPCODE_ST_WREN);
75                 b47s->cc_write(b47s, BCMA_CC_FLASHADDR, erase->addr);
76                 /* Newer flashes have "sub-sectors" which can be erased
77                  * independently with a new command: ST_SSE. The ST_SE command
78                  * erases 64KB just as before.
79                  */
80                 if (b47s->blocksize < (64 * 1024))
81                         bcm47xxsflash_cmd(b47s, OPCODE_ST_SSE);
82                 else
83                         bcm47xxsflash_cmd(b47s, OPCODE_ST_SE);
84                 break;
85         case BCM47XXSFLASH_TYPE_ATMEL:
86                 b47s->cc_write(b47s, BCMA_CC_FLASHADDR, erase->addr << 1);
87                 bcm47xxsflash_cmd(b47s, OPCODE_AT_PAGE_ERASE);
88                 break;
89         }
90
91         err = bcm47xxsflash_poll(b47s, HZ);
92         if (err)
93                 erase->state = MTD_ERASE_FAILED;
94         else
95                 erase->state = MTD_ERASE_DONE;
96
97         if (erase->callback)
98                 erase->callback(erase);
99
100         return err;
101 }
102
103 static int bcm47xxsflash_read(struct mtd_info *mtd, loff_t from, size_t len,
104                               size_t *retlen, u_char *buf)
105 {
106         struct bcm47xxsflash *b47s = mtd->priv;
107
108         /* Check address range */
109         if ((from + len) > mtd->size)
110                 return -EINVAL;
111
112         memcpy_fromio(buf, (void __iomem *)KSEG0ADDR(b47s->window + from),
113                       len);
114         *retlen = len;
115
116         return len;
117 }
118
119 static void bcm47xxsflash_fill_mtd(struct bcm47xxsflash *b47s)
120 {
121         struct mtd_info *mtd = &b47s->mtd;
122
123         mtd->priv = b47s;
124         mtd->name = "bcm47xxsflash";
125         mtd->owner = THIS_MODULE;
126         mtd->type = MTD_ROM;
127
128         /* TODO: implement writing support and verify/change following code */
129         mtd->flags = MTD_CAP_ROM;
130         mtd->size = b47s->size;
131         mtd->erasesize = b47s->blocksize;
132         mtd->writebufsize = mtd->writesize = 1;
133
134         mtd->_erase = bcm47xxsflash_erase;
135         mtd->_read = bcm47xxsflash_read;
136 }
137
138 /**************************************************
139  * BCMA
140  **************************************************/
141
142 static int bcm47xxsflash_bcma_cc_read(struct bcm47xxsflash *b47s, u16 offset)
143 {
144         return bcma_cc_read32(b47s->bcma_cc, offset);
145 }
146
147 static void bcm47xxsflash_bcma_cc_write(struct bcm47xxsflash *b47s, u16 offset,
148                                         u32 value)
149 {
150         bcma_cc_write32(b47s->bcma_cc, offset, value);
151 }
152
153 static int bcm47xxsflash_bcma_probe(struct platform_device *pdev)
154 {
155         struct bcma_sflash *sflash = dev_get_platdata(&pdev->dev);
156         struct bcm47xxsflash *b47s;
157         int err;
158
159         b47s = devm_kzalloc(&pdev->dev, sizeof(*b47s), GFP_KERNEL);
160         if (!b47s)
161                 return -ENOMEM;
162         sflash->priv = b47s;
163
164         b47s->bcma_cc = container_of(sflash, struct bcma_drv_cc, sflash);
165         b47s->cc_read = bcm47xxsflash_bcma_cc_read;
166         b47s->cc_write = bcm47xxsflash_bcma_cc_write;
167
168         switch (b47s->bcma_cc->capabilities & BCMA_CC_CAP_FLASHT) {
169         case BCMA_CC_FLASHT_STSER:
170                 b47s->type = BCM47XXSFLASH_TYPE_ST;
171                 break;
172         case BCMA_CC_FLASHT_ATSER:
173                 b47s->type = BCM47XXSFLASH_TYPE_ATMEL;
174                 break;
175         }
176
177         b47s->window = sflash->window;
178         b47s->blocksize = sflash->blocksize;
179         b47s->numblocks = sflash->numblocks;
180         b47s->size = sflash->size;
181         bcm47xxsflash_fill_mtd(b47s);
182
183         err = mtd_device_parse_register(&b47s->mtd, probes, NULL, NULL, 0);
184         if (err) {
185                 pr_err("Failed to register MTD device: %d\n", err);
186                 return err;
187         }
188
189         if (bcm47xxsflash_poll(b47s, HZ / 10))
190                 pr_warn("Serial flash busy\n");
191
192         return 0;
193 }
194
195 static int bcm47xxsflash_bcma_remove(struct platform_device *pdev)
196 {
197         struct bcma_sflash *sflash = dev_get_platdata(&pdev->dev);
198         struct bcm47xxsflash *b47s = sflash->priv;
199
200         mtd_device_unregister(&b47s->mtd);
201
202         return 0;
203 }
204
205 static struct platform_driver bcma_sflash_driver = {
206         .probe  = bcm47xxsflash_bcma_probe,
207         .remove = bcm47xxsflash_bcma_remove,
208         .driver = {
209                 .name = "bcma_sflash",
210                 .owner = THIS_MODULE,
211         },
212 };
213
214 /**************************************************
215  * Init
216  **************************************************/
217
218 module_platform_driver(bcma_sflash_driver);