drivers/i2c/busses/i2c-ali1535.c

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

File Facts

System
Linux kernel
Corpus path
drivers/i2c/busses/i2c-ali1535.c
Extension
.c
Size
15918 bytes
Lines
538
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 ali1535_driver;
static unsigned long ali1535_smba;
static unsigned short ali1535_offset;

/* Detect whether a ALI1535 can be found, and initialize it, where necessary.
   Note the differences between kernels with the old PCI BIOS interface and
   newer kernels with the real PCI interface. In compat.h some things are
   defined to make the transition easier. */
static int ali1535_setup(struct pci_dev *dev)
{
	int retval;
	unsigned char temp;

	/* Check the following things:
		- SMB I/O address is initialized
		- Device is enabled
		- We can use the addresses
	*/

	retval = pci_enable_device(dev);
	if (retval) {
		dev_err(&dev->dev, "ALI1535_smb can't enable device\n");
		goto exit;
	}

	/* Determine the address of the SMBus area */
	pci_read_config_word(dev, SMBBA, &ali1535_offset);
	dev_dbg(&dev->dev, "ALI1535_smb is at offset 0x%04x\n", ali1535_offset);
	ali1535_offset &= (0xffff & ~(ALI1535_SMB_IOSIZE - 1));
	if (ali1535_offset == 0) {
		dev_warn(&dev->dev,
			"ALI1535_smb region uninitialized - upgrade BIOS?\n");
		retval = -ENODEV;
		goto exit;
	}

	if (pci_resource_flags(dev, 0) & IORESOURCE_IO)
		ali1535_smba = pci_resource_start(dev, 0) + ali1535_offset;
	else
		ali1535_smba = ali1535_offset;

	retval = acpi_check_region(ali1535_smba, ALI1535_SMB_IOSIZE,
				   ali1535_driver.name);
	if (retval)
		goto exit;

	if (!request_region(ali1535_smba, ALI1535_SMB_IOSIZE,
			    ali1535_driver.name)) {
		dev_err(&dev->dev, "ALI1535_smb region 0x%lx already in use!\n",
			ali1535_smba);
		retval = -EBUSY;
		goto exit;
	}

	/* check if whole device is enabled */
	pci_read_config_byte(dev, SMBCFG, &temp);
	if ((temp & ALI1535_SMBIO_EN) == 0) {
		dev_err(&dev->dev, "SMB device not enabled - upgrade BIOS?\n");
		retval = -ENODEV;
		goto exit_free;
	}

	/* Is SMB Host controller enabled? */
	pci_read_config_byte(dev, SMBHSTCFG, &temp);
	if ((temp & 1) == 0) {
		dev_err(&dev->dev, "SMBus controller not enabled - upgrade BIOS?\n");
		retval = -ENODEV;
		goto exit_free;
	}

	/* set SMB clock to 74KHz as recommended in data sheet */
	pci_write_config_byte(dev, SMBCLK, 0x20);

	/*
	  The interrupt routing for SMB is set up in register 0x77 in the
	  1533 ISA Bridge device, NOT in the 7101 device.
	  Don't bother with finding the 1533 device and reading the register.
	if ((....... & 0x0F) == 1)
		dev_dbg(&dev->dev, "ALI1535 using Interrupt 9 for SMBus.\n");
	*/
	pci_read_config_byte(dev, SMBREV, &temp);
	dev_dbg(&dev->dev, "SMBREV = 0x%X\n", temp);
	dev_dbg(&dev->dev, "ALI1535_smba = 0x%lx\n", ali1535_smba);

	return 0;

exit_free:
	release_region(ali1535_smba, ALI1535_SMB_IOSIZE);
exit:
	return retval;

Annotation

Implementation Notes