drivers/peci/controller/peci-npcm.c

Source file repositories/reference/linux-study-clean/drivers/peci/controller/peci-npcm.c

File Facts

System
Linux kernel
Corpus path
drivers/peci/controller/peci-npcm.c
Extension
.c
Size
8359 bytes
Lines
298
Domain
Driver Families
Bucket
drivers/peci
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 npcm_peci {
	u32			cmd_timeout_ms;
	struct completion	xfer_complete;
	struct regmap		*regmap;
	u32			status;
	spinlock_t		lock; /* to sync completion status handling */
	struct peci_controller *controller;
	struct device		*dev;
	struct clk		*clk;
	int			irq;
};

static int npcm_peci_xfer(struct peci_controller *controller, u8 addr, struct peci_request *req)
{
	struct npcm_peci *priv = dev_get_drvdata(controller->dev.parent);
	unsigned long timeout = msecs_to_jiffies(priv->cmd_timeout_ms);
	unsigned int msg_rd;
	u32 cmd_sts;
	int i, ret;

	/* Check command sts and bus idle state */
	ret = regmap_read_poll_timeout(priv->regmap, NPCM_PECI_CTL_STS, cmd_sts,
				       !(cmd_sts & NPCM_PECI_CTRL_START_BUSY),
				       NPCM_PECI_IDLE_CHECK_INTERVAL_USEC,
				       NPCM_PECI_IDLE_CHECK_TIMEOUT_USEC);
	if (ret)
		return ret; /* -ETIMEDOUT */

	spin_lock_irq(&priv->lock);
	reinit_completion(&priv->xfer_complete);

	regmap_write(priv->regmap, NPCM_PECI_ADDR, addr);
	regmap_write(priv->regmap, NPCM_PECI_RD_LENGTH, NPCM_PECI_WR_LEN_MASK & req->rx.len);
	regmap_write(priv->regmap, NPCM_PECI_WR_LENGTH, NPCM_PECI_WR_LEN_MASK & req->tx.len);

	if (req->tx.len) {
		regmap_write(priv->regmap, NPCM_PECI_CMD, req->tx.buf[0]);

		for (i = 0; i < (req->tx.len - 1); i++)
			regmap_write(priv->regmap, NPCM_PECI_DAT_INOUT(i), req->tx.buf[i + 1]);
	}

#if IS_ENABLED(CONFIG_DYNAMIC_DEBUG)
	dev_dbg(priv->dev, "addr : %#02x, tx.len : %#02x, rx.len : %#02x\n",
		addr, req->tx.len, req->rx.len);
	print_hex_dump_bytes("TX : ", DUMP_PREFIX_NONE, req->tx.buf, req->tx.len);
#endif

	priv->status = 0;
	regmap_update_bits(priv->regmap, NPCM_PECI_CTL_STS, NPCM_PECI_CTRL_START_BUSY,
			   NPCM_PECI_CTRL_START_BUSY);

	spin_unlock_irq(&priv->lock);

	ret = wait_for_completion_interruptible_timeout(&priv->xfer_complete, timeout);
	if (ret < 0)
		return ret;

	if (ret == 0) {
		dev_dbg(priv->dev, "timeout waiting for a response\n");
		return -ETIMEDOUT;
	}

	spin_lock_irq(&priv->lock);

	if (priv->status != NPCM_PECI_CTRL_DONE) {
		spin_unlock_irq(&priv->lock);
		dev_dbg(priv->dev, "no valid response, status: %#02x\n", priv->status);
		return -EIO;
	}

	regmap_write(priv->regmap, NPCM_PECI_CMD, 0);

	for (i = 0; i < req->rx.len; i++) {
		regmap_read(priv->regmap, NPCM_PECI_DAT_INOUT(i), &msg_rd);
		req->rx.buf[i] = (u8)msg_rd;
	}

	spin_unlock_irq(&priv->lock);

#if IS_ENABLED(CONFIG_DYNAMIC_DEBUG)
	print_hex_dump_bytes("RX : ", DUMP_PREFIX_NONE, req->rx.buf, req->rx.len);
#endif
	return 0;
}

static irqreturn_t npcm_peci_irq_handler(int irq, void *arg)
{
	struct npcm_peci *priv = arg;
	u32 status_ack = 0;

Annotation

Implementation Notes