drivers/mfd/intel-m10-bmc-pmci.c

Source file repositories/reference/linux-study-clean/drivers/mfd/intel-m10-bmc-pmci.c

File Facts

System
Linux kernel
Corpus path
drivers/mfd/intel-m10-bmc-pmci.c
Extension
.c
Size
12137 bytes
Lines
458
Domain
Driver Families
Bucket
drivers/mfd
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 m10bmc_pmci_device {
	void __iomem *base;
	struct intel_m10bmc m10bmc;
	struct mutex flash_mutex;	/* protects flash_busy and serializes flash read/read */
	bool flash_busy;
};

/*
 * Intel FGPA indirect register access via hardware controller/bridge.
 */
#define INDIRECT_CMD_OFF	0
#define INDIRECT_CMD_CLR	0
#define INDIRECT_CMD_RD		BIT(0)
#define INDIRECT_CMD_WR		BIT(1)
#define INDIRECT_CMD_ACK	BIT(2)

#define INDIRECT_ADDR_OFF	0x4
#define INDIRECT_RD_OFF		0x8
#define INDIRECT_WR_OFF		0xc

#define INDIRECT_INT_US		1
#define INDIRECT_TIMEOUT_US	10000

struct indirect_ctx {
	void __iomem *base;
	struct device *dev;
};

static int indirect_clear_cmd(struct indirect_ctx *ctx)
{
	unsigned int cmd;
	int ret;

	writel(INDIRECT_CMD_CLR, ctx->base + INDIRECT_CMD_OFF);

	ret = readl_poll_timeout(ctx->base + INDIRECT_CMD_OFF, cmd,
				 cmd == INDIRECT_CMD_CLR,
				 INDIRECT_INT_US, INDIRECT_TIMEOUT_US);
	if (ret)
		dev_err(ctx->dev, "timed out waiting clear cmd (residual cmd=0x%x)\n", cmd);

	return ret;
}

static int indirect_reg_read(void *context, unsigned int reg, unsigned int *val)
{
	struct indirect_ctx *ctx = context;
	unsigned int cmd, ack, tmpval;
	int ret, ret2;

	cmd = readl(ctx->base + INDIRECT_CMD_OFF);
	if (cmd != INDIRECT_CMD_CLR)
		dev_warn(ctx->dev, "residual cmd 0x%x on read entry\n", cmd);

	writel(reg, ctx->base + INDIRECT_ADDR_OFF);
	writel(INDIRECT_CMD_RD, ctx->base + INDIRECT_CMD_OFF);

	ret = readl_poll_timeout(ctx->base + INDIRECT_CMD_OFF, ack,
				 (ack & INDIRECT_CMD_ACK) == INDIRECT_CMD_ACK,
				 INDIRECT_INT_US, INDIRECT_TIMEOUT_US);
	if (ret)
		dev_err(ctx->dev, "read timed out on reg 0x%x ack 0x%x\n", reg, ack);
	else
		tmpval = readl(ctx->base + INDIRECT_RD_OFF);

	ret2 = indirect_clear_cmd(ctx);

	if (ret)
		return ret;
	if (ret2)
		return ret2;

	*val = tmpval;
	return 0;
}

static int indirect_reg_write(void *context, unsigned int reg, unsigned int val)
{
	struct indirect_ctx *ctx = context;
	unsigned int cmd, ack;
	int ret, ret2;

	cmd = readl(ctx->base + INDIRECT_CMD_OFF);
	if (cmd != INDIRECT_CMD_CLR)
		dev_warn(ctx->dev, "residual cmd 0x%x on write entry\n", cmd);

	writel(val, ctx->base + INDIRECT_WR_OFF);
	writel(reg, ctx->base + INDIRECT_ADDR_OFF);
	writel(INDIRECT_CMD_WR, ctx->base + INDIRECT_CMD_OFF);

Annotation

Implementation Notes