drivers/soundwire/cadence_master.c

Source file repositories/reference/linux-study-clean/drivers/soundwire/cadence_master.c

File Facts

System
Linux kernel
Corpus path
drivers/soundwire/cadence_master.c
Extension
.c
Size
73119 bytes
Lines
2728
Domain
Driver Families
Bucket
drivers/soundwire
Inferred role
Driver Families: exported/initcall integration point
Status
integration 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

if (!(cdns->response_buf[i] & CDNS_MCP_RESP_ACK)) {
			no_ack = 1;
			dev_vdbg(cdns->dev, "Msg Ack not received, cmd %d\n", i);
		}
		if (cdns->response_buf[i] & CDNS_MCP_RESP_NACK) {
			nack = 1;
			dev_err_ratelimited(cdns->dev, "Msg NACK received, cmd %d\n", i);
		}
	}

	if (nack) {
		dev_err_ratelimited(cdns->dev, "Msg NACKed for Slave %d\n", msg->dev_num);
		return SDW_CMD_FAIL;
	}

	if (no_ack) {
		dev_dbg_ratelimited(cdns->dev, "Msg ignored for Slave %d\n", msg->dev_num);
		return SDW_CMD_IGNORED;
	}

	if (msg->flags == SDW_MSG_FLAG_READ) {
		/* fill response */
		for (i = 0; i < count; i++)
			msg->buf[i + offset] = FIELD_GET(CDNS_MCP_RESP_RDATA,
							 cdns->response_buf[i]);
	}

	return SDW_CMD_OK;
}

static void cdns_read_response(struct sdw_cdns *cdns)
{
	u32 num_resp, cmd_base;
	int i;

	/* RX_FIFO_AVAIL can be 2 entries more than the FIFO size */
	BUILD_BUG_ON(ARRAY_SIZE(cdns->response_buf) < CDNS_MCP_CMD_LEN + 2);

	num_resp = cdns_readl(cdns, CDNS_MCP_FIFOSTAT);
	num_resp &= CDNS_MCP_RX_FIFO_AVAIL;
	if (num_resp > ARRAY_SIZE(cdns->response_buf)) {
		dev_warn(cdns->dev, "RX AVAIL %d too long\n", num_resp);
		num_resp = ARRAY_SIZE(cdns->response_buf);
	}

	cmd_base = CDNS_IP_MCP_CMD_BASE;

	for (i = 0; i < num_resp; i++) {
		cdns->response_buf[i] = cdns_ip_readl(cdns, cmd_base);
		cmd_base += CDNS_MCP_CMD_WORD_LEN;
	}
}

static enum sdw_command_response
_cdns_xfer_msg(struct sdw_cdns *cdns, struct sdw_msg *msg, int cmd,
	       int offset, int count, bool defer)
{
	unsigned long time;
	u32 base, i, data;
	u16 addr;

	/* Program the watermark level for RX FIFO */
	if (cdns->msg_count != count) {
		cdns_writel(cdns, CDNS_MCP_FIFOLEVEL, count);
		cdns->msg_count = count;
	}

	base = CDNS_IP_MCP_CMD_BASE;
	addr = msg->addr + offset;

	for (i = 0; i < count; i++) {
		data = FIELD_PREP(CDNS_MCP_CMD_DEV_ADDR, msg->dev_num);
		data |= FIELD_PREP(CDNS_MCP_CMD_COMMAND, cmd);
		data |= FIELD_PREP(CDNS_MCP_CMD_REG_ADDR, addr);
		addr++;

		if (msg->flags == SDW_MSG_FLAG_WRITE)
			data |= msg->buf[i + offset];

		data |= FIELD_PREP(CDNS_MCP_CMD_SSP_TAG, msg->ssp_sync);
		cdns_ip_writel(cdns, base, data);
		base += CDNS_MCP_CMD_WORD_LEN;
	}

	if (defer)
		return SDW_CMD_OK;

	/* wait for timeout or response */
	time = wait_for_completion_timeout(&cdns->tx_complete,
					   msecs_to_jiffies(CDNS_TX_TIMEOUT));

Annotation

Implementation Notes