15fe42d5bSRafał Miłecki #include <linux/kernel.h> 25fe42d5bSRafał Miłecki #include <linux/module.h> 35fe42d5bSRafał Miłecki #include <linux/slab.h> 4bddcb5e7SRafał Miłecki #include <linux/delay.h> 55651d6aaSBrian Norris #include <linux/ioport.h> 65fe42d5bSRafał Miłecki #include <linux/mtd/mtd.h> 75fe42d5bSRafał Miłecki #include <linux/platform_device.h> 85fe42d5bSRafał Miłecki #include <linux/bcma/bcma.h> 95fe42d5bSRafał Miłecki 10a2f74a7dSRafał Miłecki #include "bcm47xxsflash.h" 11a2f74a7dSRafał Miłecki 125fe42d5bSRafał Miłecki MODULE_LICENSE("GPL"); 135fe42d5bSRafał Miłecki MODULE_DESCRIPTION("Serial flash driver for BCMA bus"); 145fe42d5bSRafał Miłecki 15afffeec9SArtem Bityutskiy static const char * const probes[] = { "bcm47xxpart", NULL }; 165fe42d5bSRafał Miłecki 17bddcb5e7SRafał Miłecki /************************************************** 18bddcb5e7SRafał Miłecki * Various helpers 19bddcb5e7SRafał Miłecki **************************************************/ 20bddcb5e7SRafał Miłecki 21bddcb5e7SRafał Miłecki static void bcm47xxsflash_cmd(struct bcm47xxsflash *b47s, u32 opcode) 22bddcb5e7SRafał Miłecki { 23bddcb5e7SRafał Miłecki int i; 24bddcb5e7SRafał Miłecki 25bddcb5e7SRafał Miłecki b47s->cc_write(b47s, BCMA_CC_FLASHCTL, BCMA_CC_FLASHCTL_START | opcode); 26bddcb5e7SRafał Miłecki for (i = 0; i < 1000; i++) { 27bddcb5e7SRafał Miłecki if (!(b47s->cc_read(b47s, BCMA_CC_FLASHCTL) & 28bddcb5e7SRafał Miłecki BCMA_CC_FLASHCTL_BUSY)) 29bddcb5e7SRafał Miłecki return; 30bddcb5e7SRafał Miłecki cpu_relax(); 31bddcb5e7SRafał Miłecki } 32bddcb5e7SRafał Miłecki pr_err("Control command failed (timeout)!\n"); 33bddcb5e7SRafał Miłecki } 34bddcb5e7SRafał Miłecki 35bddcb5e7SRafał Miłecki static int bcm47xxsflash_poll(struct bcm47xxsflash *b47s, int timeout) 36bddcb5e7SRafał Miłecki { 37bddcb5e7SRafał Miłecki unsigned long deadline = jiffies + timeout; 38bddcb5e7SRafał Miłecki 39bddcb5e7SRafał Miłecki do { 40bddcb5e7SRafał Miłecki switch (b47s->type) { 41bddcb5e7SRafał Miłecki case BCM47XXSFLASH_TYPE_ST: 42bddcb5e7SRafał Miłecki bcm47xxsflash_cmd(b47s, OPCODE_ST_RDSR); 43bddcb5e7SRafał Miłecki if (!(b47s->cc_read(b47s, BCMA_CC_FLASHDATA) & 44bddcb5e7SRafał Miłecki SR_ST_WIP)) 45bddcb5e7SRafał Miłecki return 0; 46bddcb5e7SRafał Miłecki break; 47bddcb5e7SRafał Miłecki case BCM47XXSFLASH_TYPE_ATMEL: 48bddcb5e7SRafał Miłecki bcm47xxsflash_cmd(b47s, OPCODE_AT_STATUS); 49bddcb5e7SRafał Miłecki if (b47s->cc_read(b47s, BCMA_CC_FLASHDATA) & 50bddcb5e7SRafał Miłecki SR_AT_READY) 51bddcb5e7SRafał Miłecki return 0; 52bddcb5e7SRafał Miłecki break; 53bddcb5e7SRafał Miłecki } 54bddcb5e7SRafał Miłecki 55bddcb5e7SRafał Miłecki cpu_relax(); 56bddcb5e7SRafał Miłecki udelay(1); 57bddcb5e7SRafał Miłecki } while (!time_after_eq(jiffies, deadline)); 58bddcb5e7SRafał Miłecki 59bddcb5e7SRafał Miłecki pr_err("Timeout waiting for flash to be ready!\n"); 60bddcb5e7SRafał Miłecki 61bddcb5e7SRafał Miłecki return -EBUSY; 62bddcb5e7SRafał Miłecki } 63bddcb5e7SRafał Miłecki 64bddcb5e7SRafał Miłecki /************************************************** 65bddcb5e7SRafał Miłecki * MTD ops 66bddcb5e7SRafał Miłecki **************************************************/ 67bddcb5e7SRafał Miłecki 68c0fcbc56SRafał Miłecki static int bcm47xxsflash_erase(struct mtd_info *mtd, struct erase_info *erase) 69c0fcbc56SRafał Miłecki { 70c0fcbc56SRafał Miłecki struct bcm47xxsflash *b47s = mtd->priv; 71c0fcbc56SRafał Miłecki int err; 72c0fcbc56SRafał Miłecki 73c0fcbc56SRafał Miłecki switch (b47s->type) { 74c0fcbc56SRafał Miłecki case BCM47XXSFLASH_TYPE_ST: 75c0fcbc56SRafał Miłecki bcm47xxsflash_cmd(b47s, OPCODE_ST_WREN); 76c0fcbc56SRafał Miłecki b47s->cc_write(b47s, BCMA_CC_FLASHADDR, erase->addr); 77c0fcbc56SRafał Miłecki /* Newer flashes have "sub-sectors" which can be erased 78c0fcbc56SRafał Miłecki * independently with a new command: ST_SSE. The ST_SE command 79c0fcbc56SRafał Miłecki * erases 64KB just as before. 80c0fcbc56SRafał Miłecki */ 81c0fcbc56SRafał Miłecki if (b47s->blocksize < (64 * 1024)) 82c0fcbc56SRafał Miłecki bcm47xxsflash_cmd(b47s, OPCODE_ST_SSE); 83c0fcbc56SRafał Miłecki else 84c0fcbc56SRafał Miłecki bcm47xxsflash_cmd(b47s, OPCODE_ST_SE); 85c0fcbc56SRafał Miłecki break; 86c0fcbc56SRafał Miłecki case BCM47XXSFLASH_TYPE_ATMEL: 87c0fcbc56SRafał Miłecki b47s->cc_write(b47s, BCMA_CC_FLASHADDR, erase->addr << 1); 88c0fcbc56SRafał Miłecki bcm47xxsflash_cmd(b47s, OPCODE_AT_PAGE_ERASE); 89c0fcbc56SRafał Miłecki break; 90c0fcbc56SRafał Miłecki } 91c0fcbc56SRafał Miłecki 92c0fcbc56SRafał Miłecki err = bcm47xxsflash_poll(b47s, HZ); 93c0fcbc56SRafał Miłecki if (err) 94c0fcbc56SRafał Miłecki erase->state = MTD_ERASE_FAILED; 95c0fcbc56SRafał Miłecki else 96c0fcbc56SRafał Miłecki erase->state = MTD_ERASE_DONE; 97c0fcbc56SRafał Miłecki 98c0fcbc56SRafał Miłecki if (erase->callback) 99c0fcbc56SRafał Miłecki erase->callback(erase); 100c0fcbc56SRafał Miłecki 101c0fcbc56SRafał Miłecki return err; 102c0fcbc56SRafał Miłecki } 103c0fcbc56SRafał Miłecki 1045fe42d5bSRafał Miłecki static int bcm47xxsflash_read(struct mtd_info *mtd, loff_t from, size_t len, 1055fe42d5bSRafał Miłecki size_t *retlen, u_char *buf) 1065fe42d5bSRafał Miłecki { 107a2f74a7dSRafał Miłecki struct bcm47xxsflash *b47s = mtd->priv; 108*ccc38234SRafał Miłecki size_t orig_len = len; 1095fe42d5bSRafał Miłecki 1105fe42d5bSRafał Miłecki /* Check address range */ 1115fe42d5bSRafał Miłecki if ((from + len) > mtd->size) 1125fe42d5bSRafał Miłecki return -EINVAL; 1135fe42d5bSRafał Miłecki 114*ccc38234SRafał Miłecki /* Read as much as possible using fast MMIO window */ 115*ccc38234SRafał Miłecki if (from < BCM47XXSFLASH_WINDOW_SZ) { 116*ccc38234SRafał Miłecki size_t memcpy_len; 1175fe42d5bSRafał Miłecki 118*ccc38234SRafał Miłecki memcpy_len = min(len, (size_t)(BCM47XXSFLASH_WINDOW_SZ - from)); 119*ccc38234SRafał Miłecki memcpy_fromio(buf, b47s->window + from, memcpy_len); 120*ccc38234SRafał Miłecki from += memcpy_len; 121*ccc38234SRafał Miłecki len -= memcpy_len; 122*ccc38234SRafał Miłecki buf += memcpy_len; 123*ccc38234SRafał Miłecki } 124*ccc38234SRafał Miłecki 125*ccc38234SRafał Miłecki /* Use indirect access for content out of the window */ 126*ccc38234SRafał Miłecki for (; len; len--) { 127*ccc38234SRafał Miłecki b47s->cc_write(b47s, BCMA_CC_FLASHADDR, from++); 128*ccc38234SRafał Miłecki bcm47xxsflash_cmd(b47s, OPCODE_ST_READ4B); 129*ccc38234SRafał Miłecki *buf++ = b47s->cc_read(b47s, BCMA_CC_FLASHDATA); 130*ccc38234SRafał Miłecki } 131*ccc38234SRafał Miłecki 132*ccc38234SRafał Miłecki *retlen = orig_len; 133*ccc38234SRafał Miłecki 134*ccc38234SRafał Miłecki return orig_len; 1355fe42d5bSRafał Miłecki } 1365fe42d5bSRafał Miłecki 13713134f48SRafał Miłecki static int bcm47xxsflash_write_st(struct mtd_info *mtd, u32 offset, size_t len, 13813134f48SRafał Miłecki const u_char *buf) 13913134f48SRafał Miłecki { 14013134f48SRafał Miłecki struct bcm47xxsflash *b47s = mtd->priv; 14113134f48SRafał Miłecki int written = 0; 14213134f48SRafał Miłecki 14313134f48SRafał Miłecki /* Enable writes */ 14413134f48SRafał Miłecki bcm47xxsflash_cmd(b47s, OPCODE_ST_WREN); 14513134f48SRafał Miłecki 14613134f48SRafał Miłecki /* Write first byte */ 14713134f48SRafał Miłecki b47s->cc_write(b47s, BCMA_CC_FLASHADDR, offset); 14813134f48SRafał Miłecki b47s->cc_write(b47s, BCMA_CC_FLASHDATA, *buf++); 14913134f48SRafał Miłecki 15013134f48SRafał Miłecki /* Program page */ 15113134f48SRafał Miłecki if (b47s->bcma_cc->core->id.rev < 20) { 15213134f48SRafał Miłecki bcm47xxsflash_cmd(b47s, OPCODE_ST_PP); 15313134f48SRafał Miłecki return 1; /* 1B written */ 15413134f48SRafał Miłecki } 15513134f48SRafał Miłecki 15613134f48SRafał Miłecki /* Program page and set CSA (on newer chips we can continue writing) */ 15713134f48SRafał Miłecki bcm47xxsflash_cmd(b47s, OPCODE_ST_CSA | OPCODE_ST_PP); 15813134f48SRafał Miłecki offset++; 15913134f48SRafał Miłecki len--; 16013134f48SRafał Miłecki written++; 16113134f48SRafał Miłecki 16213134f48SRafał Miłecki while (len > 0) { 16313134f48SRafał Miłecki /* Page boundary, another function call is needed */ 16413134f48SRafał Miłecki if ((offset & 0xFF) == 0) 16513134f48SRafał Miłecki break; 16613134f48SRafał Miłecki 16713134f48SRafał Miłecki bcm47xxsflash_cmd(b47s, OPCODE_ST_CSA | *buf++); 16813134f48SRafał Miłecki offset++; 16913134f48SRafał Miłecki len--; 17013134f48SRafał Miłecki written++; 17113134f48SRafał Miłecki } 17213134f48SRafał Miłecki 17313134f48SRafał Miłecki /* All done, drop CSA & poll */ 17413134f48SRafał Miłecki b47s->cc_write(b47s, BCMA_CC_FLASHCTL, 0); 17513134f48SRafał Miłecki udelay(1); 17613134f48SRafał Miłecki if (bcm47xxsflash_poll(b47s, HZ / 10)) 17713134f48SRafał Miłecki pr_err("Flash rejected dropping CSA\n"); 17813134f48SRafał Miłecki 17913134f48SRafał Miłecki return written; 18013134f48SRafał Miłecki } 18113134f48SRafał Miłecki 18213134f48SRafał Miłecki static int bcm47xxsflash_write_at(struct mtd_info *mtd, u32 offset, size_t len, 18313134f48SRafał Miłecki const u_char *buf) 18413134f48SRafał Miłecki { 18513134f48SRafał Miłecki struct bcm47xxsflash *b47s = mtd->priv; 18613134f48SRafał Miłecki u32 mask = b47s->blocksize - 1; 18713134f48SRafał Miłecki u32 page = (offset & ~mask) << 1; 18813134f48SRafał Miłecki u32 byte = offset & mask; 18913134f48SRafał Miłecki int written = 0; 19013134f48SRafał Miłecki 19113134f48SRafał Miłecki /* If we don't overwrite whole page, read it to the buffer first */ 19213134f48SRafał Miłecki if (byte || (len < b47s->blocksize)) { 19313134f48SRafał Miłecki int err; 19413134f48SRafał Miłecki 19513134f48SRafał Miłecki b47s->cc_write(b47s, BCMA_CC_FLASHADDR, page); 19613134f48SRafał Miłecki bcm47xxsflash_cmd(b47s, OPCODE_AT_BUF1_LOAD); 19713134f48SRafał Miłecki /* 250 us for AT45DB321B */ 19813134f48SRafał Miłecki err = bcm47xxsflash_poll(b47s, HZ / 1000); 19913134f48SRafał Miłecki if (err) { 20013134f48SRafał Miłecki pr_err("Timeout reading page 0x%X info buffer\n", page); 20113134f48SRafał Miłecki return err; 20213134f48SRafał Miłecki } 20313134f48SRafał Miłecki } 20413134f48SRafał Miłecki 20513134f48SRafał Miłecki /* Change buffer content with our data */ 20613134f48SRafał Miłecki while (len > 0) { 20713134f48SRafał Miłecki /* Page boundary, another function call is needed */ 20813134f48SRafał Miłecki if (byte == b47s->blocksize) 20913134f48SRafał Miłecki break; 21013134f48SRafał Miłecki 21113134f48SRafał Miłecki b47s->cc_write(b47s, BCMA_CC_FLASHADDR, byte++); 21213134f48SRafał Miłecki b47s->cc_write(b47s, BCMA_CC_FLASHDATA, *buf++); 21313134f48SRafał Miłecki bcm47xxsflash_cmd(b47s, OPCODE_AT_BUF1_WRITE); 21413134f48SRafał Miłecki len--; 21513134f48SRafał Miłecki written++; 21613134f48SRafał Miłecki } 21713134f48SRafał Miłecki 21813134f48SRafał Miłecki /* Program page with the buffer content */ 21913134f48SRafał Miłecki b47s->cc_write(b47s, BCMA_CC_FLASHADDR, page); 22013134f48SRafał Miłecki bcm47xxsflash_cmd(b47s, OPCODE_AT_BUF1_PROGRAM); 22113134f48SRafał Miłecki 22213134f48SRafał Miłecki return written; 22313134f48SRafał Miłecki } 22413134f48SRafał Miłecki 22513134f48SRafał Miłecki static int bcm47xxsflash_write(struct mtd_info *mtd, loff_t to, size_t len, 22613134f48SRafał Miłecki size_t *retlen, const u_char *buf) 22713134f48SRafał Miłecki { 22813134f48SRafał Miłecki struct bcm47xxsflash *b47s = mtd->priv; 22913134f48SRafał Miłecki int written; 23013134f48SRafał Miłecki 23113134f48SRafał Miłecki /* Writing functions can return without writing all passed data, for 23213134f48SRafał Miłecki * example when the hardware is too old or when we git page boundary. 23313134f48SRafał Miłecki */ 23413134f48SRafał Miłecki while (len > 0) { 23513134f48SRafał Miłecki switch (b47s->type) { 23613134f48SRafał Miłecki case BCM47XXSFLASH_TYPE_ST: 23713134f48SRafał Miłecki written = bcm47xxsflash_write_st(mtd, to, len, buf); 23813134f48SRafał Miłecki break; 23913134f48SRafał Miłecki case BCM47XXSFLASH_TYPE_ATMEL: 24013134f48SRafał Miłecki written = bcm47xxsflash_write_at(mtd, to, len, buf); 24113134f48SRafał Miłecki break; 24213134f48SRafał Miłecki default: 24313134f48SRafał Miłecki BUG_ON(1); 24413134f48SRafał Miłecki } 24513134f48SRafał Miłecki if (written < 0) { 24613134f48SRafał Miłecki pr_err("Error writing at offset 0x%llX\n", to); 24713134f48SRafał Miłecki return written; 24813134f48SRafał Miłecki } 24913134f48SRafał Miłecki to += (loff_t)written; 25013134f48SRafał Miłecki len -= written; 25113134f48SRafał Miłecki *retlen += written; 25213134f48SRafał Miłecki buf += written; 25313134f48SRafał Miłecki } 25413134f48SRafał Miłecki 25513134f48SRafał Miłecki return 0; 25613134f48SRafał Miłecki } 25713134f48SRafał Miłecki 258eb98198fSFrans Klaver static void bcm47xxsflash_fill_mtd(struct bcm47xxsflash *b47s, 259eb98198fSFrans Klaver struct device *dev) 2605fe42d5bSRafał Miłecki { 261a2f74a7dSRafał Miłecki struct mtd_info *mtd = &b47s->mtd; 262a2f74a7dSRafał Miłecki 263a2f74a7dSRafał Miłecki mtd->priv = b47s; 264eb98198fSFrans Klaver mtd->dev.parent = dev; 2655fe42d5bSRafał Miłecki mtd->name = "bcm47xxsflash"; 2665fe42d5bSRafał Miłecki 26713134f48SRafał Miłecki mtd->type = MTD_NORFLASH; 26813134f48SRafał Miłecki mtd->flags = MTD_CAP_NORFLASH; 269c0fcbc56SRafał Miłecki mtd->size = b47s->size; 270c0fcbc56SRafał Miłecki mtd->erasesize = b47s->blocksize; 27113134f48SRafał Miłecki mtd->writesize = 1; 27213134f48SRafał Miłecki mtd->writebufsize = 1; 273c0fcbc56SRafał Miłecki 274c0fcbc56SRafał Miłecki mtd->_erase = bcm47xxsflash_erase; 275c0fcbc56SRafał Miłecki mtd->_read = bcm47xxsflash_read; 27613134f48SRafał Miłecki mtd->_write = bcm47xxsflash_write; 2775fe42d5bSRafał Miłecki } 2785fe42d5bSRafał Miłecki 279f1a7c9d3SRafał Miłecki /************************************************** 280f1a7c9d3SRafał Miłecki * BCMA 281f1a7c9d3SRafał Miłecki **************************************************/ 282f1a7c9d3SRafał Miłecki 283265dfbd9SRafał Miłecki static int bcm47xxsflash_bcma_cc_read(struct bcm47xxsflash *b47s, u16 offset) 284265dfbd9SRafał Miłecki { 285265dfbd9SRafał Miłecki return bcma_cc_read32(b47s->bcma_cc, offset); 286265dfbd9SRafał Miłecki } 287265dfbd9SRafał Miłecki 288265dfbd9SRafał Miłecki static void bcm47xxsflash_bcma_cc_write(struct bcm47xxsflash *b47s, u16 offset, 289265dfbd9SRafał Miłecki u32 value) 290265dfbd9SRafał Miłecki { 291265dfbd9SRafał Miłecki bcma_cc_write32(b47s->bcma_cc, offset, value); 292265dfbd9SRafał Miłecki } 293265dfbd9SRafał Miłecki 294f1a7c9d3SRafał Miłecki static int bcm47xxsflash_bcma_probe(struct platform_device *pdev) 2955fe42d5bSRafał Miłecki { 2965651d6aaSBrian Norris struct device *dev = &pdev->dev; 2975651d6aaSBrian Norris struct bcma_sflash *sflash = dev_get_platdata(dev); 298a2f74a7dSRafał Miłecki struct bcm47xxsflash *b47s; 2995651d6aaSBrian Norris struct resource *res; 3005fe42d5bSRafał Miłecki int err; 3015fe42d5bSRafał Miłecki 3025651d6aaSBrian Norris b47s = devm_kzalloc(dev, sizeof(*b47s), GFP_KERNEL); 303d2b1bd14SLibo Chen if (!b47s) 304d2b1bd14SLibo Chen return -ENOMEM; 3055fe42d5bSRafał Miłecki 3065651d6aaSBrian Norris res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 3075651d6aaSBrian Norris if (!res) { 3085651d6aaSBrian Norris dev_err(dev, "invalid resource\n"); 3095651d6aaSBrian Norris return -EINVAL; 3105651d6aaSBrian Norris } 3115651d6aaSBrian Norris if (!devm_request_mem_region(dev, res->start, resource_size(res), 3125651d6aaSBrian Norris res->name)) { 3135651d6aaSBrian Norris dev_err(dev, "can't request region for resource %pR\n", res); 3145651d6aaSBrian Norris return -EBUSY; 3155651d6aaSBrian Norris } 31664ad4637SRafał Miłecki 31764ad4637SRafał Miłecki b47s->bcma_cc = container_of(sflash, struct bcma_drv_cc, sflash); 31864ad4637SRafał Miłecki b47s->cc_read = bcm47xxsflash_bcma_cc_read; 31964ad4637SRafał Miłecki b47s->cc_write = bcm47xxsflash_bcma_cc_write; 32064ad4637SRafał Miłecki 32164ad4637SRafał Miłecki /* 32264ad4637SRafał Miłecki * On old MIPS devices cache was magically invalidated when needed, 32364ad4637SRafał Miłecki * allowing us to use cached access and gain some performance. Trying 32464ad4637SRafał Miłecki * the same on ARM based BCM53573 results in flash corruptions, we need 32564ad4637SRafał Miłecki * to use uncached access for it. 32664ad4637SRafał Miłecki * 32764ad4637SRafał Miłecki * It may be arch specific, but right now there is only 1 ARM SoC using 32864ad4637SRafał Miłecki * this driver, so let's follow Broadcom's reference code and check 32964ad4637SRafał Miłecki * ChipCommon revision. 33064ad4637SRafał Miłecki */ 33164ad4637SRafał Miłecki if (b47s->bcma_cc->core->id.rev == 54) 33264ad4637SRafał Miłecki b47s->window = ioremap_nocache(res->start, resource_size(res)); 33364ad4637SRafał Miłecki else 3345651d6aaSBrian Norris b47s->window = ioremap_cache(res->start, resource_size(res)); 3355651d6aaSBrian Norris if (!b47s->window) { 3365651d6aaSBrian Norris dev_err(dev, "ioremap failed for resource %pR\n", res); 3375651d6aaSBrian Norris return -ENOMEM; 3385651d6aaSBrian Norris } 3395651d6aaSBrian Norris 3401f816bc7SRafał Miłecki switch (b47s->bcma_cc->capabilities & BCMA_CC_CAP_FLASHT) { 3411f816bc7SRafał Miłecki case BCMA_CC_FLASHT_STSER: 3421f816bc7SRafał Miłecki b47s->type = BCM47XXSFLASH_TYPE_ST; 3431f816bc7SRafał Miłecki break; 3441f816bc7SRafał Miłecki case BCMA_CC_FLASHT_ATSER: 3451f816bc7SRafał Miłecki b47s->type = BCM47XXSFLASH_TYPE_ATMEL; 3461f816bc7SRafał Miłecki break; 3471f816bc7SRafał Miłecki } 3481f816bc7SRafał Miłecki 349a2f74a7dSRafał Miłecki b47s->blocksize = sflash->blocksize; 350a2f74a7dSRafał Miłecki b47s->numblocks = sflash->numblocks; 351a2f74a7dSRafał Miłecki b47s->size = sflash->size; 352eb98198fSFrans Klaver bcm47xxsflash_fill_mtd(b47s, &pdev->dev); 353a2f74a7dSRafał Miłecki 354be5e5099SRafał Miłecki platform_set_drvdata(pdev, b47s); 355be5e5099SRafał Miłecki 356a2f74a7dSRafał Miłecki err = mtd_device_parse_register(&b47s->mtd, probes, NULL, NULL, 0); 3575fe42d5bSRafał Miłecki if (err) { 3585fe42d5bSRafał Miłecki pr_err("Failed to register MTD device: %d\n", err); 3595651d6aaSBrian Norris iounmap(b47s->window); 360d2b1bd14SLibo Chen return err; 3615fe42d5bSRafał Miłecki } 3625fe42d5bSRafał Miłecki 363bddcb5e7SRafał Miłecki if (bcm47xxsflash_poll(b47s, HZ / 10)) 364bddcb5e7SRafał Miłecki pr_warn("Serial flash busy\n"); 365bddcb5e7SRafał Miłecki 3665fe42d5bSRafał Miłecki return 0; 3675fe42d5bSRafał Miłecki } 3685fe42d5bSRafał Miłecki 369f1a7c9d3SRafał Miłecki static int bcm47xxsflash_bcma_remove(struct platform_device *pdev) 3705fe42d5bSRafał Miłecki { 371be5e5099SRafał Miłecki struct bcm47xxsflash *b47s = platform_get_drvdata(pdev); 3725fe42d5bSRafał Miłecki 373a2f74a7dSRafał Miłecki mtd_device_unregister(&b47s->mtd); 3745651d6aaSBrian Norris iounmap(b47s->window); 3755fe42d5bSRafał Miłecki 3765fe42d5bSRafał Miłecki return 0; 3775fe42d5bSRafał Miłecki } 3785fe42d5bSRafał Miłecki 3795fe42d5bSRafał Miłecki static struct platform_driver bcma_sflash_driver = { 380f1a7c9d3SRafał Miłecki .probe = bcm47xxsflash_bcma_probe, 381f1a7c9d3SRafał Miłecki .remove = bcm47xxsflash_bcma_remove, 3825fe42d5bSRafał Miłecki .driver = { 3835fe42d5bSRafał Miłecki .name = "bcma_sflash", 3845fe42d5bSRafał Miłecki }, 3855fe42d5bSRafał Miłecki }; 3865fe42d5bSRafał Miłecki 387f1a7c9d3SRafał Miłecki /************************************************** 388f1a7c9d3SRafał Miłecki * Init 389f1a7c9d3SRafał Miłecki **************************************************/ 390f1a7c9d3SRafał Miłecki 3918268df26SLibo Chen module_platform_driver(bcma_sflash_driver); 392