drivers/mtd/devices/bcm47xxsflash.c

Source file repositories/reference/linux-study-clean/drivers/mtd/devices/bcm47xxsflash.c

File Facts

System
Linux kernel
Corpus path
drivers/mtd/devices/bcm47xxsflash.c
Extension
.c
Size
9779 bytes
Lines
381
Domain
Driver Families
Bucket
drivers/mtd
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

switch (b47s->type) {
		case BCM47XXSFLASH_TYPE_ST:
			bcm47xxsflash_cmd(b47s, OPCODE_ST_RDSR);
			if (!(b47s->cc_read(b47s, BCMA_CC_FLASHDATA) &
			      SR_ST_WIP))
				return 0;
			break;
		case BCM47XXSFLASH_TYPE_ATMEL:
			bcm47xxsflash_cmd(b47s, OPCODE_AT_STATUS);
			if (b47s->cc_read(b47s, BCMA_CC_FLASHDATA) &
			    SR_AT_READY)
				return 0;
			break;
		}

		cpu_relax();
		udelay(1);
	} while (!time_after_eq(jiffies, deadline));

	pr_err("Timeout waiting for flash to be ready!\n");

	return -EBUSY;
}

/**************************************************
 * MTD ops
 **************************************************/

static int bcm47xxsflash_erase(struct mtd_info *mtd, struct erase_info *erase)
{
	struct bcm47xxsflash *b47s = mtd->priv;

	switch (b47s->type) {
	case BCM47XXSFLASH_TYPE_ST:
		bcm47xxsflash_cmd(b47s, OPCODE_ST_WREN);
		b47s->cc_write(b47s, BCMA_CC_FLASHADDR, erase->addr);
		/* Newer flashes have "sub-sectors" which can be erased
		 * independently with a new command: ST_SSE. The ST_SE command
		 * erases 64KB just as before.
		 */
		if (b47s->blocksize < (64 * 1024))
			bcm47xxsflash_cmd(b47s, OPCODE_ST_SSE);
		else
			bcm47xxsflash_cmd(b47s, OPCODE_ST_SE);
		break;
	case BCM47XXSFLASH_TYPE_ATMEL:
		b47s->cc_write(b47s, BCMA_CC_FLASHADDR, erase->addr << 1);
		bcm47xxsflash_cmd(b47s, OPCODE_AT_PAGE_ERASE);
		break;
	}

	return bcm47xxsflash_poll(b47s, HZ);
}

static int bcm47xxsflash_read(struct mtd_info *mtd, loff_t from, size_t len,
			      size_t *retlen, u_char *buf)
{
	struct bcm47xxsflash *b47s = mtd->priv;
	size_t orig_len = len;

	/* Check address range */
	if ((from + len) > mtd->size)
		return -EINVAL;

	/* Read as much as possible using fast MMIO window */
	if (from < BCM47XXSFLASH_WINDOW_SZ) {
		size_t memcpy_len;

		memcpy_len = min(len, (size_t)(BCM47XXSFLASH_WINDOW_SZ - from));
		memcpy_fromio(buf, b47s->window + from, memcpy_len);
		from += memcpy_len;
		len -= memcpy_len;
		buf += memcpy_len;
	}

	/* Use indirect access for content out of the window */
	for (; len; len--) {
		b47s->cc_write(b47s, BCMA_CC_FLASHADDR, from++);
		bcm47xxsflash_cmd(b47s, OPCODE_ST_READ4B);
		*buf++ = b47s->cc_read(b47s, BCMA_CC_FLASHDATA);
	}

	*retlen = orig_len;

	return orig_len;
}

static int bcm47xxsflash_write_st(struct mtd_info *mtd, u32 offset, size_t len,
				  const u_char *buf)
{

Annotation

Implementation Notes