drivers/i2c/busses/i2c-amd-mp2-plat.c

Source file repositories/reference/linux-study-clean/drivers/i2c/busses/i2c-amd-mp2-plat.c

File Facts

System
Linux kernel
Corpus path
drivers/i2c/busses/i2c-amd-mp2-plat.c
Extension
.c
Size
9614 bytes
Lines
361
Domain
Driver Families
Bucket
drivers/i2c
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 amd_i2c_dev {
	struct amd_i2c_common common;
	struct platform_device *pdev;
	struct i2c_adapter adap;
	struct completion cmd_complete;
};

#define amd_i2c_dev_common(__common) \
	container_of(__common, struct amd_i2c_dev, common)

static int i2c_amd_dma_map(struct amd_i2c_common *i2c_common)
{
	struct device *dev_pci = &i2c_common->mp2_dev->pci_dev->dev;
	struct amd_i2c_dev *i2c_dev = amd_i2c_dev_common(i2c_common);
	enum dma_data_direction dma_direction =
			i2c_common->msg->flags & I2C_M_RD ?
			DMA_FROM_DEVICE : DMA_TO_DEVICE;

	i2c_common->dma_buf = i2c_get_dma_safe_msg_buf(i2c_common->msg, 0);
	i2c_common->dma_addr = dma_map_single(dev_pci, i2c_common->dma_buf,
					      i2c_common->msg->len,
					      dma_direction);

	if (unlikely(dma_mapping_error(dev_pci, i2c_common->dma_addr))) {
		dev_err(&i2c_dev->pdev->dev,
			"Error while mapping dma buffer %p\n",
			i2c_common->dma_buf);
		return -EIO;
	}

	return 0;
}

static void i2c_amd_dma_unmap(struct amd_i2c_common *i2c_common)
{
	struct device *dev_pci = &i2c_common->mp2_dev->pci_dev->dev;
	enum dma_data_direction dma_direction =
			i2c_common->msg->flags & I2C_M_RD ?
			DMA_FROM_DEVICE : DMA_TO_DEVICE;

	dma_unmap_single(dev_pci, i2c_common->dma_addr,
			 i2c_common->msg->len, dma_direction);

	i2c_put_dma_safe_msg_buf(i2c_common->dma_buf, i2c_common->msg, true);
}

static void i2c_amd_start_cmd(struct amd_i2c_dev *i2c_dev)
{
	struct amd_i2c_common *i2c_common = &i2c_dev->common;

	reinit_completion(&i2c_dev->cmd_complete);
	i2c_common->cmd_success = false;
}

static void i2c_amd_cmd_completion(struct amd_i2c_common *i2c_common)
{
	struct amd_i2c_dev *i2c_dev = amd_i2c_dev_common(i2c_common);
	union i2c_event *event = &i2c_common->eventval;

	if (event->r.status == i2c_readcomplete_event)
		dev_dbg(&i2c_dev->pdev->dev, "readdata:%*ph\n", event->r.length,
			i2c_common->msg->buf);

	complete(&i2c_dev->cmd_complete);
}

static int i2c_amd_check_cmd_completion(struct amd_i2c_dev *i2c_dev)
{
	struct amd_i2c_common *i2c_common = &i2c_dev->common;
	unsigned long time_left;

	time_left = wait_for_completion_timeout(&i2c_dev->cmd_complete,
						i2c_dev->adap.timeout);

	if ((i2c_common->reqcmd == i2c_read ||
	     i2c_common->reqcmd == i2c_write) &&
	    i2c_common->msg->len > 32)
		i2c_amd_dma_unmap(i2c_common);

	if (time_left == 0) {
		amd_mp2_rw_timeout(i2c_common);
		return -ETIMEDOUT;
	}

	amd_mp2_process_event(i2c_common);

	if (!i2c_common->cmd_success)
		return -EIO;

	return 0;

Annotation

Implementation Notes