drivers/i2c/busses/i2c-sis5595.c

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

File Facts

System
Linux kernel
Corpus path
drivers/i2c/busses/i2c-sis5595.c
Extension
.c
Size
11250 bytes
Lines
423
Domain
Driver Families
Bucket
drivers/i2c
Inferred role
Driver Families: operation-table or driver-model contract
Status
pattern 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

static struct pci_driver sis5595_driver;
static unsigned short sis5595_base;
static struct pci_dev *sis5595_pdev;

static u8 sis5595_read(u8 reg)
{
	outb(reg, sis5595_base + SMB_INDEX);
	return inb(sis5595_base + SMB_DAT);
}

static void sis5595_write(u8 reg, u8 data)
{
	outb(reg, sis5595_base + SMB_INDEX);
	outb(data, sis5595_base + SMB_DAT);
}

static int sis5595_setup(struct pci_dev *SIS5595_dev)
{
	u16 a;
	u8 val;
	int *i;
	int retval;

	/* Look for imposters */
	for (i = blacklist; *i != 0; i++) {
		struct pci_dev *dev;
		dev = pci_get_device(PCI_VENDOR_ID_SI, *i, NULL);
		if (dev) {
			dev_err(&SIS5595_dev->dev, "Looked for SIS5595 but found unsupported device %.4x\n", *i);
			pci_dev_put(dev);
			return -ENODEV;
		}
	}

	/* Determine the address of the SMBus areas */
	pci_read_config_word(SIS5595_dev, ACPI_BASE, &sis5595_base);
	if (sis5595_base == 0 && force_addr == 0) {
		dev_err(&SIS5595_dev->dev, "ACPI base address uninitialized - upgrade BIOS or use force_addr=0xaddr\n");
		return -ENODEV;
	}

	if (force_addr)
		sis5595_base = force_addr & ~(SIS5595_EXTENT - 1);
	dev_dbg(&SIS5595_dev->dev, "ACPI Base address: %04x\n", sis5595_base);

	/* NB: We grab just the two SMBus registers here, but this may still
	 * interfere with ACPI :-(  */
	retval = acpi_check_region(sis5595_base + SMB_INDEX, 2,
				   sis5595_driver.name);
	if (retval)
		return retval;

	if (!request_region(sis5595_base + SMB_INDEX, 2,
			    sis5595_driver.name)) {
		dev_err(&SIS5595_dev->dev, "SMBus registers 0x%04x-0x%04x already in use!\n",
			sis5595_base + SMB_INDEX, sis5595_base + SMB_INDEX + 1);
		return -ENODEV;
	}

	if (force_addr) {
		dev_info(&SIS5595_dev->dev, "forcing ISA address 0x%04X\n", sis5595_base);
		retval = pci_write_config_word(SIS5595_dev, ACPI_BASE, sis5595_base);
		if (retval != PCIBIOS_SUCCESSFUL)
			goto error;
		retval = pci_read_config_word(SIS5595_dev, ACPI_BASE, &a);
		if (retval != PCIBIOS_SUCCESSFUL)
			goto error;
		if ((a & ~(SIS5595_EXTENT - 1)) != sis5595_base) {
			/* doesn't work for some chips! */
			dev_err(&SIS5595_dev->dev, "force address failed - not supported?\n");
			goto error;
		}
	}

	retval = pci_read_config_byte(SIS5595_dev, SIS5595_ENABLE_REG, &val);
	if (retval != PCIBIOS_SUCCESSFUL)
		goto error;
	if ((val & 0x80) == 0) {
		dev_info(&SIS5595_dev->dev, "enabling ACPI\n");
		retval = pci_write_config_byte(SIS5595_dev, SIS5595_ENABLE_REG, val | 0x80);
		if (retval != PCIBIOS_SUCCESSFUL)
			goto error;
		retval = pci_read_config_byte(SIS5595_dev, SIS5595_ENABLE_REG, &val);
		if (retval != PCIBIOS_SUCCESSFUL)
			goto error;
		if ((val & 0x80) == 0) {
			/* doesn't work for some chips? */
			dev_err(&SIS5595_dev->dev, "ACPI enable failed - not supported?\n");
			goto error;
		}

Annotation

Implementation Notes