Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 974d6a37 authored by Amaury Decrême's avatar Amaury Decrême Committed by Wolfram Sang
Browse files

i2c: sis630: Add SIS964 support

parent b08369a1
Loading
Loading
Loading
Loading
+9 −0
Original line number Original line Diff line number Diff line
@@ -4,9 +4,11 @@ Supported adapters:
  * Silicon Integrated Systems Corp (SiS)
  * Silicon Integrated Systems Corp (SiS)
	630 chipset (Datasheet: available at http://www.sfr-fresh.com/linux)
	630 chipset (Datasheet: available at http://www.sfr-fresh.com/linux)
	730 chipset
	730 chipset
	964 chipset
  * Possible other SiS chipsets ?
  * Possible other SiS chipsets ?


Author: Alexander Malysh <amalysh@web.de>
Author: Alexander Malysh <amalysh@web.de>
	Amaury Decrême <amaury.decreme@gmail.com> - SiS964 support


Module Parameters
Module Parameters
-----------------
-----------------
@@ -18,6 +20,7 @@ Module Parameters
* high_clock = [1|0] Forcibly set Host Master Clock to 56KHz (default,
* high_clock = [1|0] Forcibly set Host Master Clock to 56KHz (default,
			what your BIOS use). DANGEROUS! This should be a bit
			what your BIOS use). DANGEROUS! This should be a bit
			faster, but freeze some systems (i.e. my Laptop).
			faster, but freeze some systems (i.e. my Laptop).
			SIS630/730 chip only.




Description
Description
@@ -36,6 +39,12 @@ or like this:
00:00.0 Host bridge: Silicon Integrated Systems [SiS] 730 Host (rev 02)
00:00.0 Host bridge: Silicon Integrated Systems [SiS] 730 Host (rev 02)
00:01.0 ISA bridge: Silicon Integrated Systems [SiS] 85C503/5513
00:01.0 ISA bridge: Silicon Integrated Systems [SiS] 85C503/5513


or like this:

00:00.0 Host bridge: Silicon Integrated Systems [SiS] 760/M760 Host (rev 02)
00:02.0 ISA bridge: Silicon Integrated Systems [SiS] SiS964 [MuTIOL Media IO]
							LPC Controller (rev 36)

in your 'lspci' output , then this driver is for your chipset.
in your 'lspci' output , then this driver is for your chipset.


Thank You
Thank You
+2 −2
Original line number Original line Diff line number Diff line
@@ -197,11 +197,11 @@ config I2C_SIS5595
	  will be called i2c-sis5595.
	  will be called i2c-sis5595.


config I2C_SIS630
config I2C_SIS630
	tristate "SiS 630/730"
	tristate "SiS 630/730/964"
	depends on PCI
	depends on PCI
	help
	help
	  If you say yes to this option, support will be included for the
	  If you say yes to this option, support will be included for the
	  SiS630 and SiS730 SMBus (a subset of I2C) interface.
	  SiS630, SiS730 and SiS964 SMBus (a subset of I2C) interface.


	  This driver can also be built as a module.  If so, the module
	  This driver can also be built as a module.  If so, the module
	  will be called i2c-sis630.
	  will be called i2c-sis630.
+58 −30
Original line number Original line Diff line number Diff line
@@ -41,6 +41,20 @@
   Supports:
   Supports:
	SIS 630
	SIS 630
	SIS 730
	SIS 730
	SIS 964

   Notable differences between chips:
	+------------------------+--------------------+-------------------+
	|                        |     SIS630/730     |      SIS964       |
	+------------------------+--------------------+-------------------+
	| Clock                  | 14kHz/56kHz        | 55.56kHz/27.78kHz |
	| SMBus registers offset | 0x80               | 0xE0              |
	| SMB_CNT                | Bit 1 = Slave Busy | Bit 1 = Bus probe |
	|         (not used yet) | Bit 3 is reserved  | Bit 3 = Last byte |
	| SMB_PCOUNT		 | Offset + 0x06      | Offset + 0x14     |
	| SMB_COUNT              | 4:0 bits           | 5:0 bits          |
	+------------------------+--------------------+-------------------+
	(Other differences don't affect the functions provided by the driver)


   Note: we assume there can only be one device, with one SMBus interface.
   Note: we assume there can only be one device, with one SMBus interface.
*/
*/
@@ -55,22 +69,21 @@
#include <linux/acpi.h>
#include <linux/acpi.h>
#include <linux/io.h>
#include <linux/io.h>


/* SIS630 SMBus registers */
/* SIS964 id is defined here as we are the only file using it */
#define SMB_STS			0x80	/* status */
#define PCI_DEVICE_ID_SI_964	0x0964
#define SMB_EN			0x81	/* status enable */

#define SMB_CNT			0x82
/* SIS630/730/964 SMBus registers */
#define SMBHOST_CNT		0x83
#define SMB_STS			0x00	/* status */
#define SMB_ADDR		0x84
#define SMB_CNT			0x02	/* control */
#define SMB_CMD			0x85
#define SMBHOST_CNT		0x03	/* host control */
#define SMB_PCOUNT		0x86	/* processed count */
#define SMB_ADDR		0x04	/* address */
#define SMB_COUNT		0x87
#define SMB_CMD			0x05	/* command */
#define SMB_BYTE		0x88	/* ~0x8F data byte field */
#define SMB_COUNT		0x07	/* byte count */
#define SMBDEV_ADDR		0x90
#define SMB_BYTE		0x08	/* ~0x8F data byte field */
#define SMB_DB0			0x91

#define SMB_DB1			0x92
/* register count for request_region
#define SMB_SAA			0x93
 * As we don't use SMB_PCOUNT, 20 is ok for SiS630 and SiS964

 */
/* register count for request_region */
#define SIS630_SMB_IOREGION	20
#define SIS630_SMB_IOREGION	20


/* PCI address constants */
/* PCI address constants */
@@ -96,28 +109,30 @@ static struct pci_driver sis630_driver;
static bool high_clock;
static bool high_clock;
static bool force;
static bool force;
module_param(high_clock, bool, 0);
module_param(high_clock, bool, 0);
MODULE_PARM_DESC(high_clock, "Set Host Master Clock to 56KHz (default 14KHz).");
MODULE_PARM_DESC(high_clock,
	"Set Host Master Clock to 56KHz (default 14KHz) (SIS630/730 only).");
module_param(force, bool, 0);
module_param(force, bool, 0);
MODULE_PARM_DESC(force, "Forcibly enable the SIS630. DANGEROUS!");
MODULE_PARM_DESC(force, "Forcibly enable the SIS630. DANGEROUS!");


/* acpi base address */
/* SMBus base adress */
static unsigned short acpi_base;
static unsigned short smbus_base;


/* supported chips */
/* supported chips */
static int supported[] = {
static int supported[] = {
	PCI_DEVICE_ID_SI_630,
	PCI_DEVICE_ID_SI_630,
	PCI_DEVICE_ID_SI_730,
	PCI_DEVICE_ID_SI_730,
	PCI_DEVICE_ID_SI_760,
	0 /* terminates the list */
	0 /* terminates the list */
};
};


static inline u8 sis630_read(u8 reg)
static inline u8 sis630_read(u8 reg)
{
{
	return inb(acpi_base + reg);
	return inb(smbus_base + reg);
}
}


static inline void sis630_write(u8 reg, u8 data)
static inline void sis630_write(u8 reg, u8 data)
{
{
	outb(data, acpi_base + reg);
	outb(data, smbus_base + reg);
}
}


static int sis630_transaction_start(struct i2c_adapter *adap, int size, u8 *oldclock)
static int sis630_transaction_start(struct i2c_adapter *adap, int size, u8 *oldclock)
@@ -394,6 +409,8 @@ static int sis630_setup(struct pci_dev *sis630_dev)
	unsigned char b;
	unsigned char b;
	struct pci_dev *dummy = NULL;
	struct pci_dev *dummy = NULL;
	int retval, i;
	int retval, i;
	/* acpi base address */
	unsigned short acpi_base;


	/* check for supported SiS devices */
	/* check for supported SiS devices */
	for (i=0; supported[i] > 0 ; i++) {
	for (i=0; supported[i] > 0 ; i++) {
@@ -438,16 +455,25 @@ static int sis630_setup(struct pci_dev *sis630_dev)


	dev_dbg(&sis630_dev->dev, "ACPI base at 0x%04x\n", acpi_base);
	dev_dbg(&sis630_dev->dev, "ACPI base at 0x%04x\n", acpi_base);


	retval = acpi_check_region(acpi_base + SMB_STS, SIS630_SMB_IOREGION,
	if (supported[i] == PCI_DEVICE_ID_SI_760)
		smbus_base = acpi_base + 0xE0;
	else
		smbus_base = acpi_base + 0x80;

	dev_dbg(&sis630_dev->dev, "SMBus base at 0x%04hx\n", smbus_base);

	retval = acpi_check_region(smbus_base + SMB_STS, SIS630_SMB_IOREGION,
				   sis630_driver.name);
				   sis630_driver.name);
	if (retval)
	if (retval)
		goto exit;
		goto exit;


	/* Everything is happy, let's grab the memory and set things up. */
	/* Everything is happy, let's grab the memory and set things up. */
	if (!request_region(acpi_base + SMB_STS, SIS630_SMB_IOREGION,
	if (!request_region(smbus_base + SMB_STS, SIS630_SMB_IOREGION,
			    sis630_driver.name)) {
			    sis630_driver.name)) {
		dev_err(&sis630_dev->dev, "SMBus registers 0x%04x-0x%04x already "
		dev_err(&sis630_dev->dev,
			"in use!\n", acpi_base + SMB_STS, acpi_base + SMB_SAA);
			"I/O Region 0x%04hx-0x%04hx for SMBus already in use.\n",
			smbus_base + SMB_STS,
			smbus_base + SMB_STS + SIS630_SMB_IOREGION - 1);
		retval = -EBUSY;
		retval = -EBUSY;
		goto exit;
		goto exit;
	}
	}
@@ -456,7 +482,7 @@ static int sis630_setup(struct pci_dev *sis630_dev)


exit:
exit:
	if (retval)
	if (retval)
		acpi_base = 0;
		smbus_base = 0;
	return retval;
	return retval;
}
}


@@ -470,11 +496,13 @@ static struct i2c_adapter sis630_adapter = {
	.owner		= THIS_MODULE,
	.owner		= THIS_MODULE,
	.class		= I2C_CLASS_HWMON | I2C_CLASS_SPD,
	.class		= I2C_CLASS_HWMON | I2C_CLASS_SPD,
	.algo		= &smbus_algorithm,
	.algo		= &smbus_algorithm,
	.retries	= 3
};
};


static DEFINE_PCI_DEVICE_TABLE(sis630_ids) = {
static DEFINE_PCI_DEVICE_TABLE(sis630_ids) = {
	{ PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503) },
	{ PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503) },
	{ PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_LPC) },
	{ PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_LPC) },
	{ PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_964) },
	{ 0, }
	{ 0, }
};
};


@@ -491,17 +519,17 @@ static int sis630_probe(struct pci_dev *dev, const struct pci_device_id *id)
	sis630_adapter.dev.parent = &dev->dev;
	sis630_adapter.dev.parent = &dev->dev;


	snprintf(sis630_adapter.name, sizeof(sis630_adapter.name),
	snprintf(sis630_adapter.name, sizeof(sis630_adapter.name),
		 "SMBus SIS630 adapter at %04x", acpi_base + SMB_STS);
		 "SMBus SIS630 adapter at %04hx", smbus_base + SMB_STS);


	return i2c_add_adapter(&sis630_adapter);
	return i2c_add_adapter(&sis630_adapter);
}
}


static void sis630_remove(struct pci_dev *dev)
static void sis630_remove(struct pci_dev *dev)
{
{
	if (acpi_base) {
	if (smbus_base) {
		i2c_del_adapter(&sis630_adapter);
		i2c_del_adapter(&sis630_adapter);
		release_region(acpi_base + SMB_STS, SIS630_SMB_IOREGION);
		release_region(smbus_base + SMB_STS, SIS630_SMB_IOREGION);
		acpi_base = 0;
		smbus_base = 0;
	}
	}
}
}