drivers/spi/spi-realtek-rtl-snand.c

Source file repositories/reference/linux-study-clean/drivers/spi/spi-realtek-rtl-snand.c

File Facts

System
Linux kernel
Corpus path
drivers/spi/spi-realtek-rtl-snand.c
Extension
.c
Size
9234 bytes
Lines
418
Domain
Driver Families
Bucket
drivers/spi
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

struct rtl_snand {
	struct device *dev;
	struct regmap *regmap;
	struct completion comp;
};

static irqreturn_t rtl_snand_irq(int irq, void *data)
{
	struct rtl_snand *snand = data;
	u32 val = 0;

	regmap_read(snand->regmap, SNAFSR, &val);
	if (val & (SNAFSR_NFCOS | SNAFSR_NFDRS | SNAFSR_NFDWS))
		return IRQ_NONE;

	regmap_write(snand->regmap, SNAFDIR, SNAFDIR_DMA_IP);
	complete(&snand->comp);

	return IRQ_HANDLED;
}

static bool rtl_snand_supports_op(struct spi_mem *mem,
				  const struct spi_mem_op *op)
{
	if (!spi_mem_default_supports_op(mem, op))
		return false;
	if (op->cmd.nbytes != 1 || op->cmd.buswidth != 1)
		return false;
	return true;
}

static void rtl_snand_set_cs(struct rtl_snand *snand, int cs, bool active)
{
	u32 val;

	if (active)
		val = ~(1 << (4 * cs));
	else
		val = ~0;

	regmap_write(snand->regmap, SNAFCCR, val);
}

static int rtl_snand_wait_ready(struct rtl_snand *snand)
{
	u32 val;

	return regmap_read_poll_timeout(snand->regmap, SNAFSR, val, !(val & SNAFSR_NFCOS),
					0, 2 * USEC_PER_MSEC);
}

static int rtl_snand_xfer_head(struct rtl_snand *snand, int cs, const struct spi_mem_op *op)
{
	int ret;
	u32 val, len = 0;

	rtl_snand_set_cs(snand, cs, true);

	val = op->cmd.opcode << 24;
	len = 1;
	if (op->addr.nbytes && op->addr.buswidth == 1) {
		val |= op->addr.val << ((3 - op->addr.nbytes) * 8);
		len += op->addr.nbytes;
	}

	ret = rtl_snand_wait_ready(snand);
	if (ret)
		return ret;

	ret = regmap_write(snand->regmap, SNAFWCMR, CMR_LEN(len));
	if (ret)
		return ret;

	ret = regmap_write(snand->regmap, SNAFWDR, val);
	if (ret)
		return ret;

	ret = rtl_snand_wait_ready(snand);
	if (ret)
		return ret;

	if (op->addr.buswidth > 1) {
		val = op->addr.val << ((3 - op->addr.nbytes) * 8);
		len = op->addr.nbytes;

		ret = regmap_write(snand->regmap, SNAFWCMR,
				   CMR_WID(op->addr.buswidth) | CMR_LEN(len));
		if (ret)
			return ret;

Annotation

Implementation Notes