drivers/spi/spi-amlogic-spifc-a4.c

Source file repositories/reference/linux-study-clean/drivers/spi/spi-amlogic-spifc-a4.c

File Facts

System
Linux kernel
Corpus path
drivers/spi/spi-amlogic-spifc-a4.c
Extension
.c
Size
31207 bytes
Lines
1202
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 aml_sfc_ecc_cfg {
	u32 stepsize;
	u32 nsteps;
	u32 strength;
	u32 oobsize;
	u32 bch;
};

struct aml_ecc_stats {
	u32 corrected;
	u32 bitflips;
	u32 failed;
};

struct aml_sfc_caps {
	struct aml_sfc_ecc_cfg *ecc_caps;
	u32 num_ecc_caps;
};

struct aml_sfc {
	struct device *dev;
	struct clk *gate_clk;
	struct clk *core_clk;
	struct spi_controller *ctrl;
	struct regmap *regmap_base;
	const struct aml_sfc_caps *caps;
	struct nand_ecc_engine ecc_eng;
	struct aml_ecc_stats ecc_stats;
	dma_addr_t daddr;
	dma_addr_t iaddr;
	u32 info_bytes;
	u32 bus_rate;
	u32 flags;
	u32 rx_adj;
	u32 cs_sel;
	u8 *data_buf;
	__le64 *info_buf;
	u8 *priv;
};

#define AML_ECC_DATA(sz, s, b)	{ .stepsize = (sz), .strength = (s), .bch = (b) }

static struct aml_sfc_ecc_cfg aml_a113l2_ecc_caps[] = {
	AML_ECC_DATA(512, 8, ECC_BCH8_512),
	AML_ECC_DATA(1024, 8, ECC_BCH8_1K),
};

static const struct aml_sfc_caps aml_a113l2_sfc_caps = {
	.ecc_caps = aml_a113l2_ecc_caps,
	.num_ecc_caps = ARRAY_SIZE(aml_a113l2_ecc_caps)
};

static struct aml_sfc *nand_to_aml_sfc(struct nand_device *nand)
{
	struct nand_ecc_engine *eng = nand->ecc.engine;

	return container_of(eng, struct aml_sfc, ecc_eng);
}

static inline void *aml_sfc_to_ecc_ctx(struct aml_sfc *sfc)
{
	return sfc->priv;
}

static int aml_sfc_wait_cmd_finish(struct aml_sfc *sfc, u64 timeout_ms)
{
	u32 cmd_size = 0;
	int ret;

	/*
	 * The SPINAND flash controller employs a two-stage pipeline:
	 * 1) command prefetch; 2) command execution.
	 *
	 * All commands are stored in the FIFO, with one prefetched for execution.
	 *
	 * There are cases where the FIFO is detected as empty, yet a command may
	 * still be in execution and a prefetched command pending execution.
	 *
	 * So, send two idle commands to ensure all previous commands have
	 * been executed.
	 */
	regmap_write(sfc->regmap_base, SFC_CMD, CMD_IDLE(sfc->cs_sel, 0));
	regmap_write(sfc->regmap_base, SFC_CMD, CMD_IDLE(sfc->cs_sel, 0));

	/* Wait for the FIFO to empty. */
	ret = regmap_read_poll_timeout(sfc->regmap_base, SFC_CMD, cmd_size,
				       !GET_CMD_SIZE(cmd_size),
				       10, timeout_ms * 1000);
	if (ret)
		dev_err(sfc->dev, "wait for empty CMD FIFO time out\n");

Annotation

Implementation Notes