drivers/mtd/nand/raw/lpc32xx_slc.c

Source file repositories/reference/linux-study-clean/drivers/mtd/nand/raw/lpc32xx_slc.c

File Facts

System
Linux kernel
Corpus path
drivers/mtd/nand/raw/lpc32xx_slc.c
Extension
.c
Size
29004 bytes
Lines
1028
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

struct lpc32xx_nand_cfg_slc {
	uint32_t wdr_clks;
	uint32_t wwidth;
	uint32_t whold;
	uint32_t wsetup;
	uint32_t rdr_clks;
	uint32_t rwidth;
	uint32_t rhold;
	uint32_t rsetup;
	struct mtd_partition *parts;
	unsigned num_parts;
};

struct lpc32xx_nand_host {
	struct nand_chip	nand_chip;
	struct lpc32xx_slc_platform_data *pdata;
	struct clk		*clk;
	struct gpio_desc	*wp_gpio;
	void __iomem		*io_base;
	struct lpc32xx_nand_cfg_slc *ncfg;

	struct completion	comp;
	struct dma_chan		*dma_chan;
	uint32_t		dma_buf_len;
	struct dma_slave_config	dma_slave_config;
	struct scatterlist	sgl;

	/*
	 * DMA and CPU addresses of ECC work area and data buffer
	 */
	uint32_t		*ecc_buf;
	uint8_t			*data_buf;
	dma_addr_t		io_base_dma;
};

static void lpc32xx_nand_setup(struct lpc32xx_nand_host *host)
{
	uint32_t clkrate, tmp;

	/* Reset SLC controller */
	writel(SLCCTRL_SW_RESET, SLC_CTRL(host->io_base));
	udelay(1000);

	/* Basic setup */
	writel(0, SLC_CFG(host->io_base));
	writel(0, SLC_IEN(host->io_base));
	writel((SLCSTAT_INT_TC | SLCSTAT_INT_RDY_EN),
		SLC_ICR(host->io_base));

	/* Get base clock for SLC block */
	clkrate = clk_get_rate(host->clk);
	if (clkrate == 0)
		clkrate = LPC32XX_DEF_BUS_RATE;

	/* Compute clock setup values */
	tmp = SLCTAC_WDR(host->ncfg->wdr_clks) |
		SLCTAC_WWIDTH(clkrate, host->ncfg->wwidth) |
		SLCTAC_WHOLD(clkrate, host->ncfg->whold) |
		SLCTAC_WSETUP(clkrate, host->ncfg->wsetup) |
		SLCTAC_RDR(host->ncfg->rdr_clks) |
		SLCTAC_RWIDTH(clkrate, host->ncfg->rwidth) |
		SLCTAC_RHOLD(clkrate, host->ncfg->rhold) |
		SLCTAC_RSETUP(clkrate, host->ncfg->rsetup);
	writel(tmp, SLC_TAC(host->io_base));
}

/*
 * Hardware specific access to control lines
 */
static void lpc32xx_nand_cmd_ctrl(struct nand_chip *chip, int cmd,
				  unsigned int ctrl)
{
	uint32_t tmp;
	struct lpc32xx_nand_host *host = nand_get_controller_data(chip);

	/* Does CE state need to be changed? */
	tmp = readl(SLC_CFG(host->io_base));
	if (ctrl & NAND_NCE)
		tmp |= SLCCFG_CE_LOW;
	else
		tmp &= ~SLCCFG_CE_LOW;
	writel(tmp, SLC_CFG(host->io_base));

	if (cmd != NAND_CMD_NONE) {
		if (ctrl & NAND_CLE)
			writel(cmd, SLC_CMD(host->io_base));
		else
			writel(cmd, SLC_ADDR(host->io_base));
	}
}

Annotation

Implementation Notes