drivers/media/common/saa7146/saa7146_i2c.c

Source file repositories/reference/linux-study-clean/drivers/media/common/saa7146/saa7146_i2c.c

File Facts

System
Linux kernel
Corpus path
drivers/media/common/saa7146/saa7146_i2c.c
Extension
.c
Size
12585 bytes
Lines
422
Domain
Driver Families
Bucket
drivers/media
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

if (timeout == -ERESTARTSYS || dev->i2c_op) {
			SAA7146_IER_DISABLE(dev, MASK_16|MASK_17);
			SAA7146_ISR_CLEAR(dev, MASK_16|MASK_17);
			if (timeout == -ERESTARTSYS)
				/* a signal arrived */
				return -ERESTARTSYS;

			pr_warn("%s %s [irq]: timed out waiting for end of xfer\n",
				dev->name, __func__);
			return -EIO;
		}
		status = saa7146_read(dev, I2C_STATUS);
	} else {
		saa7146_write(dev, I2C_STATUS,	 dev->i2c_bitrate);
		saa7146_write(dev, I2C_TRANSFER, le32_to_cpu(*dword));
		saa7146_write(dev, MC2, (MASK_00 | MASK_16));

		/* do not poll for i2c-status before upload is complete */
		timeout = jiffies + HZ/100 + 1; /* 10ms */
		while(1) {
			mc2 = (saa7146_read(dev, MC2) & 0x1);
			if( 0 != mc2 ) {
				break;
			}
			if (time_after(jiffies,timeout)) {
				pr_warn("%s %s: timed out waiting for MC2\n",
					dev->name, __func__);
				return -EIO;
			}
		}
		/* wait until we get a transfer done or error */
		timeout = jiffies + HZ/100 + 1; /* 10ms */
		/* first read usually delivers bogus results... */
		saa7146_i2c_status(dev);
		while(1) {
			status = saa7146_i2c_status(dev);
			if ((status & 0x3) != 1)
				break;
			if (time_after(jiffies,timeout)) {
				/* this is normal when probing the bus
				 * (no answer from nonexisistant device...)
				 */
				pr_warn("%s %s [poll]: timed out waiting for end of xfer\n",
					dev->name, __func__);
				return -EIO;
			}
			if (++trial < 50 && short_delay)
				udelay(10);
			else
				msleep(1);
		}
	}

	/* give a detailed status report */
	if ( 0 != (status & (SAA7146_I2C_SPERR | SAA7146_I2C_APERR |
			     SAA7146_I2C_DTERR | SAA7146_I2C_DRERR |
			     SAA7146_I2C_AL    | SAA7146_I2C_ERR   |
			     SAA7146_I2C_BUSY)) ) {

		if ( 0 == (status & SAA7146_I2C_ERR) ||
		     0 == (status & SAA7146_I2C_BUSY) ) {
			/* it may take some time until ERR goes high - ignore */
			DEB_I2C("unexpected i2c status %04x\n", status);
		}
		if( 0 != (status & SAA7146_I2C_SPERR) ) {
			DEB_I2C("error due to invalid start/stop condition\n");
		}
		if( 0 != (status & SAA7146_I2C_DTERR) ) {
			DEB_I2C("error in data transmission\n");
		}
		if( 0 != (status & SAA7146_I2C_DRERR) ) {
			DEB_I2C("error when receiving data\n");
		}
		if( 0 != (status & SAA7146_I2C_AL) ) {
			DEB_I2C("error because arbitration lost\n");
		}

		/* we handle address-errors here */
		if( 0 != (status & SAA7146_I2C_APERR) ) {
			DEB_I2C("error in address phase\n");
			return -EREMOTEIO;
		}

		return -EIO;
	}

	/* read back data, just in case we were reading ... */
	*dword = cpu_to_le32(saa7146_read(dev, I2C_TRANSFER));

	DEB_I2C("after: 0x%08x\n", *dword);

Annotation

Implementation Notes