drivers/char/hw_random/imx-rngc.c

Source file repositories/reference/linux-study-clean/drivers/char/hw_random/imx-rngc.c

File Facts

System
Linux kernel
Corpus path
drivers/char/hw_random/imx-rngc.c
Extension
.c
Size
8940 bytes
Lines
369
Domain
Driver Families
Bucket
drivers/char
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 imx_rngc {
	struct device		*dev;
	struct clk		*clk;
	void __iomem		*base;
	struct hwrng		rng;
	struct completion	rng_op_done;
	/*
	 * err_reg is written only by the irq handler and read only
	 * when interrupts are masked, we need no spinlock
	 */
	u32			err_reg;
};


static inline void imx_rngc_irq_mask_clear(struct imx_rngc *rngc)
{
	u32 ctrl, cmd;

	/* mask interrupts */
	ctrl = readl(rngc->base + RNGC_CONTROL);
	ctrl |= RNGC_CTRL_MASK_DONE | RNGC_CTRL_MASK_ERROR;
	writel(ctrl, rngc->base + RNGC_CONTROL);

	/*
	 * CLR_INT clears the interrupt only if there's no error
	 * CLR_ERR clear the interrupt and the error register if there
	 * is an error
	 */
	cmd = readl(rngc->base + RNGC_COMMAND);
	cmd |= RNGC_CMD_CLR_INT | RNGC_CMD_CLR_ERR;
	writel(cmd, rngc->base + RNGC_COMMAND);
}

static inline void imx_rngc_irq_unmask(struct imx_rngc *rngc)
{
	u32 ctrl;

	ctrl = readl(rngc->base + RNGC_CONTROL);
	ctrl &= ~(RNGC_CTRL_MASK_DONE | RNGC_CTRL_MASK_ERROR);
	writel(ctrl, rngc->base + RNGC_CONTROL);
}

static int imx_rngc_self_test(struct imx_rngc *rngc)
{
	u32 cmd;
	int ret;

	imx_rngc_irq_unmask(rngc);

	/* run self test */
	cmd = readl(rngc->base + RNGC_COMMAND);
	writel(cmd | RNGC_CMD_SELF_TEST, rngc->base + RNGC_COMMAND);

	ret = wait_for_completion_timeout(&rngc->rng_op_done,
					  usecs_to_jiffies(RNGC_SELFTEST_TIMEOUT));
	imx_rngc_irq_mask_clear(rngc);
	if (!ret)
		return -ETIMEDOUT;

	return rngc->err_reg ? -EIO : 0;
}

static int imx_rngc_read(struct hwrng *rng, void *data, size_t max, bool wait)
{
	struct imx_rngc *rngc = container_of(rng, struct imx_rngc, rng);
	unsigned int status;
	int err, retval = 0;

	err = pm_runtime_resume_and_get(rngc->dev);
	if (err)
		return err;

	while (max >= sizeof(u32)) {
		status = readl(rngc->base + RNGC_STATUS);

		/* is there some error while reading this random number? */
		if (status & RNGC_STATUS_ERROR)
			break;

		if (status & RNGC_STATUS_FIFO_LEVEL_MASK) {
			/* retrieve a random number from FIFO */
			*(u32 *)data = readl(rngc->base + RNGC_FIFO);

			retval += sizeof(u32);
			data += sizeof(u32);
			max -= sizeof(u32);
		}
	}
	pm_runtime_mark_last_busy(rngc->dev);
	pm_runtime_put(rngc->dev);

Annotation

Implementation Notes