drivers/i2c/busses/i2c-isch.c

Source file repositories/reference/linux-study-clean/drivers/i2c/busses/i2c-isch.c

File Facts

System
Linux kernel
Corpus path
drivers/i2c/busses/i2c-isch.c
Extension
.c
Size
9464 bytes
Lines
317
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 sch_i2c {
	struct i2c_adapter adapter;
	void __iomem *smba;
};

static int backbone_speed = 33000; /* backbone speed in kHz */
module_param(backbone_speed, int, 0600);
MODULE_PARM_DESC(backbone_speed, "Backbone speed in kHz, (default = 33000)");

static inline u8 sch_io_rd8(struct sch_i2c *priv, unsigned int offset)
{
	return ioread8(priv->smba + offset);
}

static inline void sch_io_wr8(struct sch_i2c *priv, unsigned int offset, u8 value)
{
	iowrite8(value, priv->smba + offset);
}

static inline u16 sch_io_rd16(struct sch_i2c *priv, unsigned int offset)
{
	return ioread16(priv->smba + offset);
}

static inline void sch_io_wr16(struct sch_i2c *priv, unsigned int offset, u16 value)
{
	iowrite16(value, priv->smba + offset);
}

/**
 * sch_transaction - Start the i2c transaction
 * @adap: the i2c adapter pointer
 *
 * The sch_access() will prepare the transaction and
 * this function will execute it.
 *
 * Return: 0 for success and others for failure.
 */
static int sch_transaction(struct i2c_adapter *adap)
{
	struct sch_i2c *priv = container_of(adap, struct sch_i2c, adapter);
	int temp;
	int rc;

	dev_dbg(&adap->dev,
		"Transaction (pre): CNT=%02x, CMD=%02x, ADD=%02x, DAT0=%02x, DAT1=%02x\n",
		sch_io_rd8(priv, SMBHSTCNT), sch_io_rd8(priv, SMBHSTCMD),
		sch_io_rd8(priv, SMBHSTADD),
		sch_io_rd8(priv, SMBHSTDAT0), sch_io_rd8(priv, SMBHSTDAT1));

	/* Make sure the SMBus host is ready to start transmitting */
	temp = sch_io_rd8(priv, SMBHSTSTS) & 0x0f;
	if (temp) {
		/* Can not be busy since we checked it in sch_access */
		if (temp & 0x01)
			dev_dbg(&adap->dev, "Completion (%02x). Clear...\n", temp);
		if (temp & 0x06)
			dev_dbg(&adap->dev, "SMBus error (%02x). Resetting...\n", temp);
		sch_io_wr8(priv, SMBHSTSTS, temp);
		temp = sch_io_rd8(priv, SMBHSTSTS) & 0x0f;
		if (temp) {
			dev_err(&adap->dev, "SMBus is not ready: (%02x)\n", temp);
			return -EAGAIN;
		}
	}

	/* Start the transaction by setting bit 4 */
	temp = sch_io_rd8(priv, SMBHSTCNT);
	temp |= 0x10;
	sch_io_wr8(priv, SMBHSTCNT, temp);

	rc = read_poll_timeout(sch_io_rd8, temp, !(temp & 0x08), 200, 500000, true, priv, SMBHSTSTS);
	/* If the SMBus is still busy, we give up */
	if (rc) {
		dev_err(&adap->dev, "SMBus Timeout!\n");
	} else if (temp & 0x04) {
		rc = -EIO;
		dev_dbg(&adap->dev, "Bus collision! SMBus may be locked until next hard reset. (sorry!)\n");
		/* Clock stops and target is stuck in mid-transmission */
	} else if (temp & 0x02) {
		rc = -EIO;
		dev_err(&adap->dev, "Error: no response!\n");
	} else if (temp & 0x01) {
		dev_dbg(&adap->dev, "Post complete!\n");
		sch_io_wr8(priv, SMBHSTSTS, temp & 0x0f);
		temp = sch_io_rd8(priv, SMBHSTSTS) & 0x07;
		if (temp & 0x06) {
			/* Completion clear failed */
			dev_dbg(&adap->dev,
				"Failed reset at end of transaction (%02x), Bus error!\n", temp);

Annotation

Implementation Notes