mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-09-04 20:19:47 +08:00
i2c: sis630: Add SIS964 support
Signed-off-by: Amaury Decrême <amaury.decreme@gmail.com> Reviewed-by: Jean Delvare <khali@linux-fr.org> Signed-off-by: Wolfram Sang <wolfram@the-dreams.de>
This commit is contained in:
parent
b08369a174
commit
974d6a3797
@ -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
|
||||||
|
@ -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.
|
||||||
|
@ -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
|
|
||||||
#define SMBHOST_CNT 0x83
|
|
||||||
#define SMB_ADDR 0x84
|
|
||||||
#define SMB_CMD 0x85
|
|
||||||
#define SMB_PCOUNT 0x86 /* processed count */
|
|
||||||
#define SMB_COUNT 0x87
|
|
||||||
#define SMB_BYTE 0x88 /* ~0x8F data byte field */
|
|
||||||
#define SMBDEV_ADDR 0x90
|
|
||||||
#define SMB_DB0 0x91
|
|
||||||
#define SMB_DB1 0x92
|
|
||||||
#define SMB_SAA 0x93
|
|
||||||
|
|
||||||
/* register count for request_region */
|
/* SIS630/730/964 SMBus registers */
|
||||||
|
#define SMB_STS 0x00 /* status */
|
||||||
|
#define SMB_CNT 0x02 /* control */
|
||||||
|
#define SMBHOST_CNT 0x03 /* host control */
|
||||||
|
#define SMB_ADDR 0x04 /* address */
|
||||||
|
#define SMB_CMD 0x05 /* command */
|
||||||
|
#define SMB_COUNT 0x07 /* byte count */
|
||||||
|
#define SMB_BYTE 0x08 /* ~0x8F data byte field */
|
||||||
|
|
||||||
|
/* register count for request_region
|
||||||
|
* As we don't use SMB_PCOUNT, 20 is ok for SiS630 and SiS964
|
||||||
|
*/
|
||||||
#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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user