提交 ddb03448 编写于 作者: L Linus Torvalds

Merge branch 'i2c-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jdelvare/staging

Pull i2c updates from Jean Delvare:
 "The most important changes here are a big cleanup of the i2c-piix4
  driver, cleanups and interrupt support to the i2c-i801 driver, and
  support for the SCCB protocol."

* 'i2c-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jdelvare/staging:
  i2c-omap: Add support for I2C_M_STOP message flag
  i2c: Fall back to emulated SMBus if the operation isn't supported natively
  i2c: Add SCCB support
  i2c-tiny-usb: Add support for the Robofuzz OSIF USB/I2C converter
  i2c-i801: Enable IRQ for byte_by_byte transactions
  i2c-i801: Enable interrupts on ICH5/7/8/9/10
  i2c-i801: Enable IRQ for SMBus transactions
  i2c-i801: Consolidate polling
  i2c-i801: Drop ENABLE_INT9
  i2c-i801: Rename some SMBHSTCNT bit constants
  i2c-i801: Check and return errors during byte-by-byte transfers
  i2c-i801: Clear only status bits in HST_STS
  i2c-i801: Refactor use of LAST_BYTE in i801_block_transaction_byte_by_byte
  i2c-smbus: Use module_i2c_driver()
  i2c/writing-clients: Mention module_i2c_driver()
  i2c-piix4: Support AMD auxiliary SMBus controller
  i2c-piix4: Separate registration and probing code
  i2c-piix4: Eliminate piix4_smba global variable
  i2c/busses: Use module_pci_driver
  i2c: Update Guenter Roeck's e-mail address
...@@ -38,9 +38,10 @@ Module Parameters ...@@ -38,9 +38,10 @@ Module Parameters
Disable selected features normally supported by the device. This makes it Disable selected features normally supported by the device. This makes it
possible to work around possible driver or hardware bugs if the feature in possible to work around possible driver or hardware bugs if the feature in
question doesn't work as intended for whatever reason. Bit values: question doesn't work as intended for whatever reason. Bit values:
1 disable SMBus PEC 0x01 disable SMBus PEC
2 disable the block buffer 0x02 disable the block buffer
8 disable the I2C block read functionality 0x08 disable the I2C block read functionality
0x10 don't use interrupts
Description Description
...@@ -86,6 +87,12 @@ SMBus 2.0 Support ...@@ -86,6 +87,12 @@ SMBus 2.0 Support
The 82801DB (ICH4) and later chips support several SMBus 2.0 features. The 82801DB (ICH4) and later chips support several SMBus 2.0 features.
Interrupt Support
-----------------
PCI interrupt support is supported on the 82801EB (ICH5) and later chips.
Hidden ICH SMBus Hidden ICH SMBus
---------------- ----------------
......
...@@ -8,6 +8,11 @@ Supported adapters: ...@@ -8,6 +8,11 @@ Supported adapters:
Datasheet: Only available via NDA from ServerWorks Datasheet: Only available via NDA from ServerWorks
* ATI IXP200, IXP300, IXP400, SB600, SB700 and SB800 southbridges * ATI IXP200, IXP300, IXP400, SB600, SB700 and SB800 southbridges
Datasheet: Not publicly available Datasheet: Not publicly available
SB700 register reference available at:
http://support.amd.com/us/Embedded_TechDocs/43009_sb7xx_rrg_pub_1.00.pdf
* AMD SP5100 (SB700 derivative found on some server mainboards)
Datasheet: Publicly available at the AMD website
http://support.amd.com/us/Embedded_TechDocs/44413.pdf
* AMD Hudson-2 * AMD Hudson-2
Datasheet: Not publicly available Datasheet: Not publicly available
* Standard Microsystems (SMSC) SLC90E66 (Victory66) southbridge * Standard Microsystems (SMSC) SLC90E66 (Victory66) southbridge
...@@ -68,6 +73,10 @@ this driver on those mainboards. ...@@ -68,6 +73,10 @@ this driver on those mainboards.
The ServerWorks Southbridges, the Intel 440MX, and the Victory66 are The ServerWorks Southbridges, the Intel 440MX, and the Victory66 are
identical to the PIIX4 in I2C/SMBus support. identical to the PIIX4 in I2C/SMBus support.
The AMD SB700 and SP5100 chipsets implement two PIIX4-compatible SMBus
controllers. If your BIOS initializes the secondary controller, it will
be detected by this driver as an "Auxiliary SMBus Host Controller".
If you own Force CPCI735 motherboard or other OSB4 based systems you may need If you own Force CPCI735 motherboard or other OSB4 based systems you may need
to change the SMBus Interrupt Select register so the SMBus controller uses to change the SMBus Interrupt Select register so the SMBus controller uses
the SMI mode. the SMI mode.
......
...@@ -245,21 +245,17 @@ static int __init foo_init(void) ...@@ -245,21 +245,17 @@ static int __init foo_init(void)
{ {
return i2c_add_driver(&foo_driver); return i2c_add_driver(&foo_driver);
} }
module_init(foo_init);
static void __exit foo_cleanup(void) static void __exit foo_cleanup(void)
{ {
i2c_del_driver(&foo_driver); i2c_del_driver(&foo_driver);
} }
module_exit(foo_cleanup);
/* Substitute your own name and email address */ The module_i2c_driver() macro can be used to reduce above code.
MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>"
MODULE_DESCRIPTION("Driver for Barf Inc. Foo I2C devices");
/* a few non-GPL license types are also allowed */
MODULE_LICENSE("GPL");
module_init(foo_init); module_i2c_driver(foo_driver);
module_exit(foo_cleanup);
Note that some functions are marked by `__init'. These functions can Note that some functions are marked by `__init'. These functions can
be removed after kernel booting (or module loading) is completed. be removed after kernel booting (or module loading) is completed.
...@@ -267,6 +263,17 @@ Likewise, functions marked by `__exit' are dropped by the compiler when ...@@ -267,6 +263,17 @@ Likewise, functions marked by `__exit' are dropped by the compiler when
the code is built into the kernel, as they would never be called. the code is built into the kernel, as they would never be called.
Driver Information
==================
/* Substitute your own name and email address */
MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>"
MODULE_DESCRIPTION("Driver for Barf Inc. Foo I2C devices");
/* a few non-GPL license types are also allowed */
MODULE_LICENSE("GPL");
Power Management Power Management
================ ================
......
...@@ -133,7 +133,7 @@ config I2C_PIIX4 ...@@ -133,7 +133,7 @@ config I2C_PIIX4
ATI IXP300 ATI IXP300
ATI IXP400 ATI IXP400
ATI SB600 ATI SB600
ATI SB700 ATI SB700/SP5100
ATI SB800 ATI SB800
AMD Hudson-2 AMD Hudson-2
Serverworks OSB4 Serverworks OSB4
...@@ -143,6 +143,10 @@ config I2C_PIIX4 ...@@ -143,6 +143,10 @@ config I2C_PIIX4
Serverworks HT-1100 Serverworks HT-1100
SMSC Victory66 SMSC Victory66
Some AMD chipsets contain two PIIX4-compatible SMBus
controllers. This driver will attempt to use both controllers
on the SB700/SP5100, if they have been initialized by the BIOS.
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-piix4. will be called i2c-piix4.
......
...@@ -531,15 +531,7 @@ static struct pci_driver ali1535_driver = { ...@@ -531,15 +531,7 @@ static struct pci_driver ali1535_driver = {
.remove = __devexit_p(ali1535_remove), .remove = __devexit_p(ali1535_remove),
}; };
static int __init i2c_ali1535_init(void) module_pci_driver(ali1535_driver);
{
return pci_register_driver(&ali1535_driver);
}
static void __exit i2c_ali1535_exit(void)
{
pci_unregister_driver(&ali1535_driver);
}
MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, " MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, "
"Philip Edelbrock <phil@netroedge.com>, " "Philip Edelbrock <phil@netroedge.com>, "
...@@ -547,6 +539,3 @@ MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, " ...@@ -547,6 +539,3 @@ MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, "
"and Dan Eaton <dan.eaton@rocketlogix.com>"); "and Dan Eaton <dan.eaton@rocketlogix.com>");
MODULE_DESCRIPTION("ALI1535 SMBus driver"); MODULE_DESCRIPTION("ALI1535 SMBus driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
module_init(i2c_ali1535_init);
module_exit(i2c_ali1535_exit);
...@@ -431,18 +431,6 @@ static struct pci_driver ali1563_pci_driver = { ...@@ -431,18 +431,6 @@ static struct pci_driver ali1563_pci_driver = {
.remove = __devexit_p(ali1563_remove), .remove = __devexit_p(ali1563_remove),
}; };
static int __init ali1563_init(void) module_pci_driver(ali1563_pci_driver);
{
return pci_register_driver(&ali1563_pci_driver);
}
module_init(ali1563_init);
static void __exit ali1563_exit(void)
{
pci_unregister_driver(&ali1563_pci_driver);
}
module_exit(ali1563_exit);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -513,21 +513,10 @@ static struct pci_driver ali15x3_driver = { ...@@ -513,21 +513,10 @@ static struct pci_driver ali15x3_driver = {
.remove = __devexit_p(ali15x3_remove), .remove = __devexit_p(ali15x3_remove),
}; };
static int __init i2c_ali15x3_init(void) module_pci_driver(ali15x3_driver);
{
return pci_register_driver(&ali15x3_driver);
}
static void __exit i2c_ali15x3_exit(void)
{
pci_unregister_driver(&ali15x3_driver);
}
MODULE_AUTHOR ("Frodo Looijaard <frodol@dds.nl>, " MODULE_AUTHOR ("Frodo Looijaard <frodol@dds.nl>, "
"Philip Edelbrock <phil@netroedge.com>, " "Philip Edelbrock <phil@netroedge.com>, "
"and Mark D. Studebaker <mdsxyz123@yahoo.com>"); "and Mark D. Studebaker <mdsxyz123@yahoo.com>");
MODULE_DESCRIPTION("ALI15X3 SMBus driver"); MODULE_DESCRIPTION("ALI15X3 SMBus driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
module_init(i2c_ali15x3_init);
module_exit(i2c_ali15x3_exit);
...@@ -410,21 +410,10 @@ static struct pci_driver amd756_driver = { ...@@ -410,21 +410,10 @@ static struct pci_driver amd756_driver = {
.remove = __devexit_p(amd756_remove), .remove = __devexit_p(amd756_remove),
}; };
static int __init amd756_init(void) module_pci_driver(amd756_driver);
{
return pci_register_driver(&amd756_driver);
}
static void __exit amd756_exit(void)
{
pci_unregister_driver(&amd756_driver);
}
MODULE_AUTHOR("Merlin Hughes <merlin@merlin.org>"); MODULE_AUTHOR("Merlin Hughes <merlin@merlin.org>");
MODULE_DESCRIPTION("AMD756/766/768/8111 and nVidia nForce SMBus driver"); MODULE_DESCRIPTION("AMD756/766/768/8111 and nVidia nForce SMBus driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
EXPORT_SYMBOL(amd756_smbus); EXPORT_SYMBOL(amd756_smbus);
module_init(amd756_init)
module_exit(amd756_exit)
...@@ -491,15 +491,4 @@ static struct pci_driver amd8111_driver = { ...@@ -491,15 +491,4 @@ static struct pci_driver amd8111_driver = {
.remove = __devexit_p(amd8111_remove), .remove = __devexit_p(amd8111_remove),
}; };
static int __init i2c_amd8111_init(void) module_pci_driver(amd8111_driver);
{
return pci_register_driver(&amd8111_driver);
}
static void __exit i2c_amd8111_exit(void)
{
pci_unregister_driver(&amd8111_driver);
}
module_init(i2c_amd8111_init);
module_exit(i2c_amd8111_exit);
...@@ -374,17 +374,7 @@ static struct pci_driver dw_i2c_driver = { ...@@ -374,17 +374,7 @@ static struct pci_driver dw_i2c_driver = {
}, },
}; };
static int __init dw_i2c_init_driver(void) module_pci_driver(dw_i2c_driver);
{
return pci_register_driver(&dw_i2c_driver);
}
module_init(dw_i2c_init_driver);
static void __exit dw_i2c_exit_driver(void)
{
pci_unregister_driver(&dw_i2c_driver);
}
module_exit(dw_i2c_exit_driver);
MODULE_AUTHOR("Baruch Siach <baruch@tkos.co.il>"); MODULE_AUTHOR("Baruch Siach <baruch@tkos.co.il>");
MODULE_DESCRIPTION("Synopsys DesignWare PCI I2C bus adapter"); MODULE_DESCRIPTION("Synopsys DesignWare PCI I2C bus adapter");
......
...@@ -517,6 +517,6 @@ static struct usb_driver diolan_u2c_driver = { ...@@ -517,6 +517,6 @@ static struct usb_driver diolan_u2c_driver = {
module_usb_driver(diolan_u2c_driver); module_usb_driver(diolan_u2c_driver);
MODULE_AUTHOR("Guenter Roeck <guenter.roeck@ericsson.com>"); MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
MODULE_DESCRIPTION(DRIVER_NAME " driver"); MODULE_DESCRIPTION(DRIVER_NAME " driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -953,17 +953,7 @@ static struct pci_driver pch_pcidriver = { ...@@ -953,17 +953,7 @@ static struct pci_driver pch_pcidriver = {
.resume = pch_i2c_resume .resume = pch_i2c_resume
}; };
static int __init pch_pci_init(void) module_pci_driver(pch_pcidriver);
{
return pci_register_driver(&pch_pcidriver);
}
module_init(pch_pci_init);
static void __exit pch_pci_exit(void)
{
pci_unregister_driver(&pch_pcidriver);
}
module_exit(pch_pci_exit);
MODULE_DESCRIPTION("Intel EG20T PCH/LAPIS Semico ML7213/ML7223/ML7831 IOH I2C"); MODULE_DESCRIPTION("Intel EG20T PCH/LAPIS Semico ML7213/ML7223/ML7831 IOH I2C");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
......
...@@ -156,23 +156,8 @@ static struct pci_driver hydra_driver = { ...@@ -156,23 +156,8 @@ static struct pci_driver hydra_driver = {
.remove = __devexit_p(hydra_remove), .remove = __devexit_p(hydra_remove),
}; };
static int __init i2c_hydra_init(void) module_pci_driver(hydra_driver);
{
return pci_register_driver(&hydra_driver);
}
static void __exit i2c_hydra_exit(void)
{
pci_unregister_driver(&hydra_driver);
}
MODULE_AUTHOR("Geert Uytterhoeven <geert@linux-m68k.org>"); MODULE_AUTHOR("Geert Uytterhoeven <geert@linux-m68k.org>");
MODULE_DESCRIPTION("i2c for Apple Hydra Mac I/O"); MODULE_DESCRIPTION("i2c for Apple Hydra Mac I/O");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
module_init(i2c_hydra_init);
module_exit(i2c_hydra_exit);
...@@ -60,10 +60,12 @@ ...@@ -60,10 +60,12 @@
Block process call transaction no Block process call transaction no
I2C block read transaction yes (doesn't use the block buffer) I2C block read transaction yes (doesn't use the block buffer)
Slave mode no Slave mode no
Interrupt processing yes
See the file Documentation/i2c/busses/i2c-i801 for details. See the file Documentation/i2c/busses/i2c-i801 for details.
*/ */
#include <linux/interrupt.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/kernel.h> #include <linux/kernel.h>
...@@ -76,6 +78,7 @@ ...@@ -76,6 +78,7 @@
#include <linux/io.h> #include <linux/io.h>
#include <linux/dmi.h> #include <linux/dmi.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/wait.h>
/* I801 SMBus address offsets */ /* I801 SMBus address offsets */
#define SMBHSTSTS(p) (0 + (p)->smba) #define SMBHSTSTS(p) (0 + (p)->smba)
...@@ -91,8 +94,12 @@ ...@@ -91,8 +94,12 @@
/* PCI Address Constants */ /* PCI Address Constants */
#define SMBBAR 4 #define SMBBAR 4
#define SMBPCISTS 0x006
#define SMBHSTCFG 0x040 #define SMBHSTCFG 0x040
/* Host status bits for SMBPCISTS */
#define SMBPCISTS_INTS 0x08
/* Host configuration bits for SMBHSTCFG */ /* Host configuration bits for SMBHSTCFG */
#define SMBHSTCFG_HST_EN 1 #define SMBHSTCFG_HST_EN 1
#define SMBHSTCFG_SMB_SMI_EN 2 #define SMBHSTCFG_SMB_SMI_EN 2
...@@ -102,12 +109,8 @@ ...@@ -102,12 +109,8 @@
#define SMBAUXCTL_CRC 1 #define SMBAUXCTL_CRC 1
#define SMBAUXCTL_E32B 2 #define SMBAUXCTL_E32B 2
/* kill bit for SMBHSTCNT */
#define SMBHSTCNT_KILL 2
/* Other settings */ /* Other settings */
#define MAX_RETRIES 400 #define MAX_RETRIES 400
#define ENABLE_INT9 0 /* set to 0x01 to enable - untested */
/* I801 command constants */ /* I801 command constants */
#define I801_QUICK 0x00 #define I801_QUICK 0x00
...@@ -117,10 +120,13 @@ ...@@ -117,10 +120,13 @@
#define I801_PROC_CALL 0x10 /* unimplemented */ #define I801_PROC_CALL 0x10 /* unimplemented */
#define I801_BLOCK_DATA 0x14 #define I801_BLOCK_DATA 0x14
#define I801_I2C_BLOCK_DATA 0x18 /* ICH5 and later */ #define I801_I2C_BLOCK_DATA 0x18 /* ICH5 and later */
#define I801_BLOCK_LAST 0x34
#define I801_I2C_BLOCK_LAST 0x38 /* ICH5 and later */ /* I801 Host Control register bits */
#define I801_START 0x40 #define SMBHSTCNT_INTREN 0x01
#define I801_PEC_EN 0x80 /* ICH3 and later */ #define SMBHSTCNT_KILL 0x02
#define SMBHSTCNT_LAST_BYTE 0x20
#define SMBHSTCNT_START 0x40
#define SMBHSTCNT_PEC_EN 0x80 /* ICH3 and later */
/* I801 Hosts Status register bits */ /* I801 Hosts Status register bits */
#define SMBHSTSTS_BYTE_DONE 0x80 #define SMBHSTSTS_BYTE_DONE 0x80
...@@ -132,9 +138,11 @@ ...@@ -132,9 +138,11 @@
#define SMBHSTSTS_INTR 0x02 #define SMBHSTSTS_INTR 0x02
#define SMBHSTSTS_HOST_BUSY 0x01 #define SMBHSTSTS_HOST_BUSY 0x01
#define STATUS_FLAGS (SMBHSTSTS_BYTE_DONE | SMBHSTSTS_FAILED | \ #define STATUS_ERROR_FLAGS (SMBHSTSTS_FAILED | SMBHSTSTS_BUS_ERR | \
SMBHSTSTS_BUS_ERR | SMBHSTSTS_DEV_ERR | \ SMBHSTSTS_DEV_ERR)
SMBHSTSTS_INTR)
#define STATUS_FLAGS (SMBHSTSTS_BYTE_DONE | SMBHSTSTS_INTR | \
STATUS_ERROR_FLAGS)
/* Older devices have their ID defined in <linux/pci_ids.h> */ /* Older devices have their ID defined in <linux/pci_ids.h> */
#define PCI_DEVICE_ID_INTEL_COUGARPOINT_SMBUS 0x1c22 #define PCI_DEVICE_ID_INTEL_COUGARPOINT_SMBUS 0x1c22
...@@ -154,6 +162,17 @@ struct i801_priv { ...@@ -154,6 +162,17 @@ struct i801_priv {
unsigned char original_hstcfg; unsigned char original_hstcfg;
struct pci_dev *pci_dev; struct pci_dev *pci_dev;
unsigned int features; unsigned int features;
/* isr processing */
wait_queue_head_t waitq;
u8 status;
/* Command state used by isr for byte-by-byte block transactions */
u8 cmd;
bool is_read;
int count;
int len;
u8 *data;
}; };
static struct pci_driver i801_driver; static struct pci_driver i801_driver;
...@@ -162,6 +181,7 @@ static struct pci_driver i801_driver; ...@@ -162,6 +181,7 @@ static struct pci_driver i801_driver;
#define FEATURE_BLOCK_BUFFER (1 << 1) #define FEATURE_BLOCK_BUFFER (1 << 1)
#define FEATURE_BLOCK_PROC (1 << 2) #define FEATURE_BLOCK_PROC (1 << 2)
#define FEATURE_I2C_BLOCK_READ (1 << 3) #define FEATURE_I2C_BLOCK_READ (1 << 3)
#define FEATURE_IRQ (1 << 4)
/* Not really a feature, but it's convenient to handle it as such */ /* Not really a feature, but it's convenient to handle it as such */
#define FEATURE_IDF (1 << 15) #define FEATURE_IDF (1 << 15)
...@@ -170,6 +190,7 @@ static const char *i801_feature_names[] = { ...@@ -170,6 +190,7 @@ static const char *i801_feature_names[] = {
"Block buffer", "Block buffer",
"Block process call", "Block process call",
"I2C block read", "I2C block read",
"Interrupt",
}; };
static unsigned int disable_features; static unsigned int disable_features;
...@@ -205,13 +226,22 @@ static int i801_check_pre(struct i801_priv *priv) ...@@ -205,13 +226,22 @@ static int i801_check_pre(struct i801_priv *priv)
return 0; return 0;
} }
/* Convert the status register to an error code, and clear it. */ /*
static int i801_check_post(struct i801_priv *priv, int status, int timeout) * Convert the status register to an error code, and clear it.
* Note that status only contains the bits we want to clear, not the
* actual register value.
*/
static int i801_check_post(struct i801_priv *priv, int status)
{ {
int result = 0; int result = 0;
/* If the SMBus is still busy, we give up */ /*
if (timeout) { * If the SMBus is still busy, we give up
* Note: This timeout condition only happens when using polling
* transactions. For interrupt operation, NAK/timeout is indicated by
* DEV_ERR.
*/
if (unlikely(status < 0)) {
dev_err(&priv->pci_dev->dev, "Transaction timeout\n"); dev_err(&priv->pci_dev->dev, "Transaction timeout\n");
/* try to stop the current command */ /* try to stop the current command */
dev_dbg(&priv->pci_dev->dev, "Terminating the current operation\n"); dev_dbg(&priv->pci_dev->dev, "Terminating the current operation\n");
...@@ -244,64 +274,76 @@ static int i801_check_post(struct i801_priv *priv, int status, int timeout) ...@@ -244,64 +274,76 @@ static int i801_check_post(struct i801_priv *priv, int status, int timeout)
dev_dbg(&priv->pci_dev->dev, "Lost arbitration\n"); dev_dbg(&priv->pci_dev->dev, "Lost arbitration\n");
} }
if (result) { /* Clear status flags except BYTE_DONE, to be cleared by caller */
/* Clear error flags */ outb_p(status, SMBHSTSTS(priv));
outb_p(status & STATUS_FLAGS, SMBHSTSTS(priv));
status = inb_p(SMBHSTSTS(priv)) & STATUS_FLAGS;
if (status) {
dev_warn(&priv->pci_dev->dev, "Failed clearing status "
"flags at end of transaction (%02x)\n",
status);
}
}
return result; return result;
} }
static int i801_transaction(struct i801_priv *priv, int xact) /* Wait for BUSY being cleared and either INTR or an error flag being set */
static int i801_wait_intr(struct i801_priv *priv)
{ {
int status;
int result;
int timeout = 0; int timeout = 0;
int status;
result = i801_check_pre(priv);
if (result < 0)
return result;
/* the current contents of SMBHSTCNT can be overwritten, since PEC,
* INTREN, SMBSCMD are passed in xact */
outb_p(xact | I801_START, SMBHSTCNT(priv));
/* We will always wait for a fraction of a second! */ /* We will always wait for a fraction of a second! */
do { do {
usleep_range(250, 500); usleep_range(250, 500);
status = inb_p(SMBHSTSTS(priv)); status = inb_p(SMBHSTSTS(priv));
} while ((status & SMBHSTSTS_HOST_BUSY) && (timeout++ < MAX_RETRIES)); } while (((status & SMBHSTSTS_HOST_BUSY) ||
!(status & (STATUS_ERROR_FLAGS | SMBHSTSTS_INTR))) &&
(timeout++ < MAX_RETRIES));
result = i801_check_post(priv, status, timeout > MAX_RETRIES); if (timeout > MAX_RETRIES) {
if (result < 0) dev_dbg(&priv->pci_dev->dev, "INTR Timeout!\n");
return result; return -ETIMEDOUT;
}
outb_p(SMBHSTSTS_INTR, SMBHSTSTS(priv)); return status & (STATUS_ERROR_FLAGS | SMBHSTSTS_INTR);
return 0;
} }
/* wait for INTR bit as advised by Intel */ /* Wait for either BYTE_DONE or an error flag being set */
static void i801_wait_hwpec(struct i801_priv *priv) static int i801_wait_byte_done(struct i801_priv *priv)
{ {
int timeout = 0; int timeout = 0;
int status; int status;
/* We will always wait for a fraction of a second! */
do { do {
usleep_range(250, 500); usleep_range(250, 500);
status = inb_p(SMBHSTSTS(priv)); status = inb_p(SMBHSTSTS(priv));
} while ((!(status & SMBHSTSTS_INTR)) } while (!(status & (STATUS_ERROR_FLAGS | SMBHSTSTS_BYTE_DONE)) &&
&& (timeout++ < MAX_RETRIES)); (timeout++ < MAX_RETRIES));
if (timeout > MAX_RETRIES) if (timeout > MAX_RETRIES) {
dev_dbg(&priv->pci_dev->dev, "PEC Timeout!\n"); dev_dbg(&priv->pci_dev->dev, "BYTE_DONE Timeout!\n");
return -ETIMEDOUT;
}
return status & STATUS_ERROR_FLAGS;
}
outb_p(status, SMBHSTSTS(priv)); static int i801_transaction(struct i801_priv *priv, int xact)
{
int status;
int result;
result = i801_check_pre(priv);
if (result < 0)
return result;
if (priv->features & FEATURE_IRQ) {
outb_p(xact | SMBHSTCNT_INTREN | SMBHSTCNT_START,
SMBHSTCNT(priv));
wait_event(priv->waitq, (status = priv->status));
priv->status = 0;
return i801_check_post(priv, status);
}
/* the current contents of SMBHSTCNT can be overwritten, since PEC,
* SMBSCMD are passed in xact */
outb_p(xact | SMBHSTCNT_START, SMBHSTCNT(priv));
status = i801_wait_intr(priv);
return i801_check_post(priv, status);
} }
static int i801_block_transaction_by_block(struct i801_priv *priv, static int i801_block_transaction_by_block(struct i801_priv *priv,
...@@ -321,8 +363,8 @@ static int i801_block_transaction_by_block(struct i801_priv *priv, ...@@ -321,8 +363,8 @@ static int i801_block_transaction_by_block(struct i801_priv *priv,
outb_p(data->block[i+1], SMBBLKDAT(priv)); outb_p(data->block[i+1], SMBBLKDAT(priv));
} }
status = i801_transaction(priv, I801_BLOCK_DATA | ENABLE_INT9 | status = i801_transaction(priv, I801_BLOCK_DATA |
I801_PEC_EN * hwpec); (hwpec ? SMBHSTCNT_PEC_EN : 0));
if (status) if (status)
return status; return status;
...@@ -338,6 +380,98 @@ static int i801_block_transaction_by_block(struct i801_priv *priv, ...@@ -338,6 +380,98 @@ static int i801_block_transaction_by_block(struct i801_priv *priv,
return 0; return 0;
} }
static void i801_isr_byte_done(struct i801_priv *priv)
{
if (priv->is_read) {
/* For SMBus block reads, length is received with first byte */
if (((priv->cmd & 0x1c) == I801_BLOCK_DATA) &&
(priv->count == 0)) {
priv->len = inb_p(SMBHSTDAT0(priv));
if (priv->len < 1 || priv->len > I2C_SMBUS_BLOCK_MAX) {
dev_err(&priv->pci_dev->dev,
"Illegal SMBus block read size %d\n",
priv->len);
/* FIXME: Recover */
priv->len = I2C_SMBUS_BLOCK_MAX;
} else {
dev_dbg(&priv->pci_dev->dev,
"SMBus block read size is %d\n",
priv->len);
}
priv->data[-1] = priv->len;
}
/* Read next byte */
if (priv->count < priv->len)
priv->data[priv->count++] = inb(SMBBLKDAT(priv));
else
dev_dbg(&priv->pci_dev->dev,
"Discarding extra byte on block read\n");
/* Set LAST_BYTE for last byte of read transaction */
if (priv->count == priv->len - 1)
outb_p(priv->cmd | SMBHSTCNT_LAST_BYTE,
SMBHSTCNT(priv));
} else if (priv->count < priv->len - 1) {
/* Write next byte, except for IRQ after last byte */
outb_p(priv->data[++priv->count], SMBBLKDAT(priv));
}
/* Clear BYTE_DONE to continue with next byte */
outb_p(SMBHSTSTS_BYTE_DONE, SMBHSTSTS(priv));
}
/*
* There are two kinds of interrupts:
*
* 1) i801 signals transaction completion with one of these interrupts:
* INTR - Success
* DEV_ERR - Invalid command, NAK or communication timeout
* BUS_ERR - SMI# transaction collision
* FAILED - transaction was canceled due to a KILL request
* When any of these occur, update ->status and wake up the waitq.
* ->status must be cleared before kicking off the next transaction.
*
* 2) For byte-by-byte (I2C read/write) transactions, one BYTE_DONE interrupt
* occurs for each byte of a byte-by-byte to prepare the next byte.
*/
static irqreturn_t i801_isr(int irq, void *dev_id)
{
struct i801_priv *priv = dev_id;
u16 pcists;
u8 status;
/* Confirm this is our interrupt */
pci_read_config_word(priv->pci_dev, SMBPCISTS, &pcists);
if (!(pcists & SMBPCISTS_INTS))
return IRQ_NONE;
status = inb_p(SMBHSTSTS(priv));
if (status != 0x42)
dev_dbg(&priv->pci_dev->dev, "irq: status = %02x\n", status);
if (status & SMBHSTSTS_BYTE_DONE)
i801_isr_byte_done(priv);
/*
* Clear irq sources and report transaction result.
* ->status must be cleared before the next transaction is started.
*/
status &= SMBHSTSTS_INTR | STATUS_ERROR_FLAGS;
if (status) {
outb_p(status, SMBHSTSTS(priv));
priv->status |= status;
wake_up(&priv->waitq);
}
return IRQ_HANDLED;
}
/*
* For "byte-by-byte" block transactions:
* I2C write uses cmd=I801_BLOCK_DATA, I2C_EN=1
* I2C read uses cmd=I801_I2C_BLOCK_DATA
*/
static int i801_block_transaction_byte_by_byte(struct i801_priv *priv, static int i801_block_transaction_byte_by_byte(struct i801_priv *priv,
union i2c_smbus_data *data, union i2c_smbus_data *data,
char read_write, int command, char read_write, int command,
...@@ -347,7 +481,6 @@ static int i801_block_transaction_byte_by_byte(struct i801_priv *priv, ...@@ -347,7 +481,6 @@ static int i801_block_transaction_byte_by_byte(struct i801_priv *priv,
int smbcmd; int smbcmd;
int status; int status;
int result; int result;
int timeout;
result = i801_check_pre(priv); result = i801_check_pre(priv);
if (result < 0) if (result < 0)
...@@ -360,36 +493,39 @@ static int i801_block_transaction_byte_by_byte(struct i801_priv *priv, ...@@ -360,36 +493,39 @@ static int i801_block_transaction_byte_by_byte(struct i801_priv *priv,
outb_p(data->block[1], SMBBLKDAT(priv)); outb_p(data->block[1], SMBBLKDAT(priv));
} }
if (command == I2C_SMBUS_I2C_BLOCK_DATA &&
read_write == I2C_SMBUS_READ)
smbcmd = I801_I2C_BLOCK_DATA;
else
smbcmd = I801_BLOCK_DATA;
if (priv->features & FEATURE_IRQ) {
priv->is_read = (read_write == I2C_SMBUS_READ);
if (len == 1 && priv->is_read)
smbcmd |= SMBHSTCNT_LAST_BYTE;
priv->cmd = smbcmd | SMBHSTCNT_INTREN;
priv->len = len;
priv->count = 0;
priv->data = &data->block[1];
outb_p(priv->cmd | SMBHSTCNT_START, SMBHSTCNT(priv));
wait_event(priv->waitq, (status = priv->status));
priv->status = 0;
return i801_check_post(priv, status);
}
for (i = 1; i <= len; i++) { for (i = 1; i <= len; i++) {
if (i == len && read_write == I2C_SMBUS_READ) { if (i == len && read_write == I2C_SMBUS_READ)
if (command == I2C_SMBUS_I2C_BLOCK_DATA) smbcmd |= SMBHSTCNT_LAST_BYTE;
smbcmd = I801_I2C_BLOCK_LAST; outb_p(smbcmd, SMBHSTCNT(priv));
else
smbcmd = I801_BLOCK_LAST;
} else {
if (command == I2C_SMBUS_I2C_BLOCK_DATA
&& read_write == I2C_SMBUS_READ)
smbcmd = I801_I2C_BLOCK_DATA;
else
smbcmd = I801_BLOCK_DATA;
}
outb_p(smbcmd | ENABLE_INT9, SMBHSTCNT(priv));
if (i == 1) if (i == 1)
outb_p(inb(SMBHSTCNT(priv)) | I801_START, outb_p(inb(SMBHSTCNT(priv)) | SMBHSTCNT_START,
SMBHSTCNT(priv)); SMBHSTCNT(priv));
/* We will always wait for a fraction of a second! */ status = i801_wait_byte_done(priv);
timeout = 0; if (status)
do { goto exit;
usleep_range(250, 500);
status = inb_p(SMBHSTSTS(priv));
} while ((!(status & SMBHSTSTS_BYTE_DONE))
&& (timeout++ < MAX_RETRIES));
result = i801_check_post(priv, status, timeout > MAX_RETRIES);
if (result < 0)
return result;
if (i == 1 && read_write == I2C_SMBUS_READ if (i == 1 && read_write == I2C_SMBUS_READ
&& command != I2C_SMBUS_I2C_BLOCK_DATA) { && command != I2C_SMBUS_I2C_BLOCK_DATA) {
...@@ -416,10 +552,12 @@ static int i801_block_transaction_byte_by_byte(struct i801_priv *priv, ...@@ -416,10 +552,12 @@ static int i801_block_transaction_byte_by_byte(struct i801_priv *priv,
outb_p(data->block[i+1], SMBBLKDAT(priv)); outb_p(data->block[i+1], SMBBLKDAT(priv));
/* signals SMBBLKDAT ready */ /* signals SMBBLKDAT ready */
outb_p(SMBHSTSTS_BYTE_DONE | SMBHSTSTS_INTR, SMBHSTSTS(priv)); outb_p(SMBHSTSTS_BYTE_DONE, SMBHSTSTS(priv));
} }
return 0; status = i801_wait_intr(priv);
exit:
return i801_check_post(priv, status);
} }
static int i801_set_block_buffer_mode(struct i801_priv *priv) static int i801_set_block_buffer_mode(struct i801_priv *priv)
...@@ -474,9 +612,6 @@ static int i801_block_transaction(struct i801_priv *priv, ...@@ -474,9 +612,6 @@ static int i801_block_transaction(struct i801_priv *priv,
read_write, read_write,
command, hwpec); command, hwpec);
if (result == 0 && hwpec)
i801_wait_hwpec(priv);
if (command == I2C_SMBUS_I2C_BLOCK_DATA if (command == I2C_SMBUS_I2C_BLOCK_DATA
&& read_write == I2C_SMBUS_WRITE) { && read_write == I2C_SMBUS_WRITE) {
/* restore saved configuration register value */ /* restore saved configuration register value */
...@@ -564,7 +699,7 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr, ...@@ -564,7 +699,7 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr,
ret = i801_block_transaction(priv, data, read_write, size, ret = i801_block_transaction(priv, data, read_write, size,
hwpec); hwpec);
else else
ret = i801_transaction(priv, xact | ENABLE_INT9); ret = i801_transaction(priv, xact);
/* Some BIOSes don't like it when PEC is enabled at reboot or resume /* Some BIOSes don't like it when PEC is enabled at reboot or resume
time, so we forcibly disable it after every transaction. Turn off time, so we forcibly disable it after every transaction. Turn off
...@@ -799,6 +934,16 @@ static int __devinit i801_probe(struct pci_dev *dev, ...@@ -799,6 +934,16 @@ static int __devinit i801_probe(struct pci_dev *dev,
break; break;
} }
/* IRQ processing tested on CougarPoint PCH, ICH5, ICH7-M and ICH10 */
if (dev->device == PCI_DEVICE_ID_INTEL_COUGARPOINT_SMBUS ||
dev->device == PCI_DEVICE_ID_INTEL_82801EB_3 ||
dev->device == PCI_DEVICE_ID_INTEL_ICH7_17 ||
dev->device == PCI_DEVICE_ID_INTEL_ICH8_5 ||
dev->device == PCI_DEVICE_ID_INTEL_ICH9_6 ||
dev->device == PCI_DEVICE_ID_INTEL_ICH10_4 ||
dev->device == PCI_DEVICE_ID_INTEL_ICH10_5)
priv->features |= FEATURE_IRQ;
/* Disable features on user request */ /* Disable features on user request */
for (i = 0; i < ARRAY_SIZE(i801_feature_names); i++) { for (i = 0; i < ARRAY_SIZE(i801_feature_names); i++) {
if (priv->features & disable_features & (1 << i)) if (priv->features & disable_features & (1 << i))
...@@ -846,16 +991,30 @@ static int __devinit i801_probe(struct pci_dev *dev, ...@@ -846,16 +991,30 @@ static int __devinit i801_probe(struct pci_dev *dev,
} }
pci_write_config_byte(priv->pci_dev, SMBHSTCFG, temp); pci_write_config_byte(priv->pci_dev, SMBHSTCFG, temp);
if (temp & SMBHSTCFG_SMB_SMI_EN) if (temp & SMBHSTCFG_SMB_SMI_EN) {
dev_dbg(&dev->dev, "SMBus using interrupt SMI#\n"); dev_dbg(&dev->dev, "SMBus using interrupt SMI#\n");
else /* Disable SMBus interrupt feature if SMBus using SMI# */
dev_dbg(&dev->dev, "SMBus using PCI Interrupt\n"); priv->features &= ~FEATURE_IRQ;
}
/* Clear special mode bits */ /* Clear special mode bits */
if (priv->features & (FEATURE_SMBUS_PEC | FEATURE_BLOCK_BUFFER)) if (priv->features & (FEATURE_SMBUS_PEC | FEATURE_BLOCK_BUFFER))
outb_p(inb_p(SMBAUXCTL(priv)) & outb_p(inb_p(SMBAUXCTL(priv)) &
~(SMBAUXCTL_CRC | SMBAUXCTL_E32B), SMBAUXCTL(priv)); ~(SMBAUXCTL_CRC | SMBAUXCTL_E32B), SMBAUXCTL(priv));
if (priv->features & FEATURE_IRQ) {
init_waitqueue_head(&priv->waitq);
err = request_irq(dev->irq, i801_isr, IRQF_SHARED,
i801_driver.name, priv);
if (err) {
dev_err(&dev->dev, "Failed to allocate irq %d: %d\n",
dev->irq, err);
goto exit_release;
}
dev_info(&dev->dev, "SMBus using PCI Interrupt\n");
}
/* set up the sysfs linkage to our parent device */ /* set up the sysfs linkage to our parent device */
priv->adapter.dev.parent = &dev->dev; priv->adapter.dev.parent = &dev->dev;
...@@ -867,14 +1026,18 @@ static int __devinit i801_probe(struct pci_dev *dev, ...@@ -867,14 +1026,18 @@ static int __devinit i801_probe(struct pci_dev *dev,
err = i2c_add_adapter(&priv->adapter); err = i2c_add_adapter(&priv->adapter);
if (err) { if (err) {
dev_err(&dev->dev, "Failed to add SMBus adapter\n"); dev_err(&dev->dev, "Failed to add SMBus adapter\n");
goto exit_release; goto exit_free_irq;
} }
i801_probe_optional_slaves(priv); i801_probe_optional_slaves(priv);
pci_set_drvdata(dev, priv); pci_set_drvdata(dev, priv);
return 0; return 0;
exit_free_irq:
if (priv->features & FEATURE_IRQ)
free_irq(dev->irq, priv);
exit_release: exit_release:
pci_release_region(dev, SMBBAR); pci_release_region(dev, SMBBAR);
exit: exit:
...@@ -888,7 +1051,11 @@ static void __devexit i801_remove(struct pci_dev *dev) ...@@ -888,7 +1051,11 @@ static void __devexit i801_remove(struct pci_dev *dev)
i2c_del_adapter(&priv->adapter); i2c_del_adapter(&priv->adapter);
pci_write_config_byte(dev, SMBHSTCFG, priv->original_hstcfg); pci_write_config_byte(dev, SMBHSTCFG, priv->original_hstcfg);
if (priv->features & FEATURE_IRQ)
free_irq(dev->irq, priv);
pci_release_region(dev, SMBBAR); pci_release_region(dev, SMBBAR);
pci_set_drvdata(dev, NULL); pci_set_drvdata(dev, NULL);
kfree(priv); kfree(priv);
/* /*
......
...@@ -1116,18 +1116,7 @@ static struct pci_driver intel_mid_i2c_driver = { ...@@ -1116,18 +1116,7 @@ static struct pci_driver intel_mid_i2c_driver = {
.remove = __devexit_p(intel_mid_i2c_remove), .remove = __devexit_p(intel_mid_i2c_remove),
}; };
static int __init intel_mid_i2c_init(void) module_pci_driver(intel_mid_i2c_driver);
{
return pci_register_driver(&intel_mid_i2c_driver);
}
static void __exit intel_mid_i2c_exit(void)
{
pci_unregister_driver(&intel_mid_i2c_driver);
}
module_init(intel_mid_i2c_init);
module_exit(intel_mid_i2c_exit);
MODULE_AUTHOR("Ba Zheng <zheng.ba@intel.com>"); MODULE_AUTHOR("Ba Zheng <zheng.ba@intel.com>");
MODULE_DESCRIPTION("I2C driver for Moorestown Platform"); MODULE_DESCRIPTION("I2C driver for Moorestown Platform");
......
...@@ -453,16 +453,4 @@ static struct pci_driver nforce2_driver = { ...@@ -453,16 +453,4 @@ static struct pci_driver nforce2_driver = {
.remove = __devexit_p(nforce2_remove), .remove = __devexit_p(nforce2_remove),
}; };
static int __init nforce2_init(void) module_pci_driver(nforce2_driver);
{
return pci_register_driver(&nforce2_driver);
}
static void __exit nforce2_exit(void)
{
pci_unregister_driver(&nforce2_driver);
}
module_init(nforce2_init);
module_exit(nforce2_exit);
...@@ -545,6 +545,8 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap, ...@@ -545,6 +545,8 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
if (dev->speed > 400) if (dev->speed > 400)
w |= OMAP_I2C_CON_OPMODE_HS; w |= OMAP_I2C_CON_OPMODE_HS;
if (msg->flags & I2C_M_STOP)
stop = 1;
if (msg->flags & I2C_M_TEN) if (msg->flags & I2C_M_TEN)
w |= OMAP_I2C_CON_XA; w |= OMAP_I2C_CON_XA;
if (!(msg->flags & I2C_M_RD)) if (!(msg->flags & I2C_M_RD))
...@@ -658,7 +660,8 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) ...@@ -658,7 +660,8 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
static u32 static u32
omap_i2c_func(struct i2c_adapter *adap) omap_i2c_func(struct i2c_adapter *adap)
{ {
return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK); return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK) |
I2C_FUNC_PROTOCOL_MANGLING;
} }
static inline void static inline void
......
...@@ -415,19 +415,8 @@ static struct pci_driver pasemi_smb_driver = { ...@@ -415,19 +415,8 @@ static struct pci_driver pasemi_smb_driver = {
.remove = __devexit_p(pasemi_smb_remove), .remove = __devexit_p(pasemi_smb_remove),
}; };
static int __init pasemi_smb_init(void) module_pci_driver(pasemi_smb_driver);
{
return pci_register_driver(&pasemi_smb_driver);
}
static void __exit pasemi_smb_exit(void)
{
pci_unregister_driver(&pasemi_smb_driver);
}
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_AUTHOR ("Olof Johansson <olof@lixom.net>"); MODULE_AUTHOR ("Olof Johansson <olof@lixom.net>");
MODULE_DESCRIPTION("PA Semi PWRficient SMBus driver"); MODULE_DESCRIPTION("PA Semi PWRficient SMBus driver");
module_init(pasemi_smb_init);
module_exit(pasemi_smb_exit);
...@@ -21,11 +21,12 @@ ...@@ -21,11 +21,12 @@
Supports: Supports:
Intel PIIX4, 440MX Intel PIIX4, 440MX
Serverworks OSB4, CSB5, CSB6, HT-1000, HT-1100 Serverworks OSB4, CSB5, CSB6, HT-1000, HT-1100
ATI IXP200, IXP300, IXP400, SB600, SB700, SB800 ATI IXP200, IXP300, IXP400, SB600, SB700/SP5100, SB800
AMD Hudson-2 AMD Hudson-2
SMSC Victory66 SMSC Victory66
Note: we assume there can only be one device, with one SMBus interface. Note: we assume there can only be one device, with one or more
SMBus interfaces.
*/ */
#include <linux/module.h> #include <linux/module.h>
...@@ -94,10 +95,8 @@ MODULE_PARM_DESC(force_addr, ...@@ -94,10 +95,8 @@ MODULE_PARM_DESC(force_addr,
"Forcibly enable the PIIX4 at the given address. " "Forcibly enable the PIIX4 at the given address. "
"EXTREMELY DANGEROUS!"); "EXTREMELY DANGEROUS!");
static unsigned short piix4_smba;
static int srvrworks_csb5_delay; static int srvrworks_csb5_delay;
static struct pci_driver piix4_driver; static struct pci_driver piix4_driver;
static struct i2c_adapter piix4_adapter;
static struct dmi_system_id __devinitdata piix4_dmi_blacklist[] = { static struct dmi_system_id __devinitdata piix4_dmi_blacklist[] = {
{ {
...@@ -127,10 +126,15 @@ static struct dmi_system_id __devinitdata piix4_dmi_ibm[] = { ...@@ -127,10 +126,15 @@ static struct dmi_system_id __devinitdata piix4_dmi_ibm[] = {
{ }, { },
}; };
struct i2c_piix4_adapdata {
unsigned short smba;
};
static int __devinit piix4_setup(struct pci_dev *PIIX4_dev, static int __devinit piix4_setup(struct pci_dev *PIIX4_dev,
const struct pci_device_id *id) const struct pci_device_id *id)
{ {
unsigned char temp; unsigned char temp;
unsigned short piix4_smba;
if ((PIIX4_dev->vendor == PCI_VENDOR_ID_SERVERWORKS) && if ((PIIX4_dev->vendor == PCI_VENDOR_ID_SERVERWORKS) &&
(PIIX4_dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5)) (PIIX4_dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5))
...@@ -206,7 +210,6 @@ static int __devinit piix4_setup(struct pci_dev *PIIX4_dev, ...@@ -206,7 +210,6 @@ static int __devinit piix4_setup(struct pci_dev *PIIX4_dev,
dev_err(&PIIX4_dev->dev, dev_err(&PIIX4_dev->dev,
"Host SMBus controller not enabled!\n"); "Host SMBus controller not enabled!\n");
release_region(piix4_smba, SMBIOSIZE); release_region(piix4_smba, SMBIOSIZE);
piix4_smba = 0;
return -ENODEV; return -ENODEV;
} }
} }
...@@ -224,12 +227,13 @@ static int __devinit piix4_setup(struct pci_dev *PIIX4_dev, ...@@ -224,12 +227,13 @@ static int __devinit piix4_setup(struct pci_dev *PIIX4_dev,
"SMBus Host Controller at 0x%x, revision %d\n", "SMBus Host Controller at 0x%x, revision %d\n",
piix4_smba, temp); piix4_smba, temp);
return 0; return piix4_smba;
} }
static int __devinit piix4_setup_sb800(struct pci_dev *PIIX4_dev, static int __devinit piix4_setup_sb800(struct pci_dev *PIIX4_dev,
const struct pci_device_id *id) const struct pci_device_id *id)
{ {
unsigned short piix4_smba;
unsigned short smba_idx = 0xcd6; unsigned short smba_idx = 0xcd6;
u8 smba_en_lo, smba_en_hi, i2ccfg, i2ccfg_offset = 0x10, smb_en = 0x2c; u8 smba_en_lo, smba_en_hi, i2ccfg, i2ccfg_offset = 0x10, smb_en = 0x2c;
...@@ -273,7 +277,6 @@ static int __devinit piix4_setup_sb800(struct pci_dev *PIIX4_dev, ...@@ -273,7 +277,6 @@ static int __devinit piix4_setup_sb800(struct pci_dev *PIIX4_dev,
dev_err(&PIIX4_dev->dev, "SMBus I2C bus config region " dev_err(&PIIX4_dev->dev, "SMBus I2C bus config region "
"0x%x already in use!\n", piix4_smba + i2ccfg_offset); "0x%x already in use!\n", piix4_smba + i2ccfg_offset);
release_region(piix4_smba, SMBIOSIZE); release_region(piix4_smba, SMBIOSIZE);
piix4_smba = 0;
return -EBUSY; return -EBUSY;
} }
i2ccfg = inb_p(piix4_smba + i2ccfg_offset); i2ccfg = inb_p(piix4_smba + i2ccfg_offset);
...@@ -288,30 +291,72 @@ static int __devinit piix4_setup_sb800(struct pci_dev *PIIX4_dev, ...@@ -288,30 +291,72 @@ static int __devinit piix4_setup_sb800(struct pci_dev *PIIX4_dev,
"SMBus Host Controller at 0x%x, revision %d\n", "SMBus Host Controller at 0x%x, revision %d\n",
piix4_smba, i2ccfg >> 4); piix4_smba, i2ccfg >> 4);
return 0; return piix4_smba;
}
static int __devinit piix4_setup_aux(struct pci_dev *PIIX4_dev,
const struct pci_device_id *id,
unsigned short base_reg_addr)
{
/* Set up auxiliary SMBus controllers found on some
* AMD chipsets e.g. SP5100 (SB700 derivative) */
unsigned short piix4_smba;
/* Read address of auxiliary SMBus controller */
pci_read_config_word(PIIX4_dev, base_reg_addr, &piix4_smba);
if ((piix4_smba & 1) == 0) {
dev_dbg(&PIIX4_dev->dev,
"Auxiliary SMBus controller not enabled\n");
return -ENODEV;
}
piix4_smba &= 0xfff0;
if (piix4_smba == 0) {
dev_dbg(&PIIX4_dev->dev,
"Auxiliary SMBus base address uninitialized\n");
return -ENODEV;
}
if (acpi_check_region(piix4_smba, SMBIOSIZE, piix4_driver.name))
return -ENODEV;
if (!request_region(piix4_smba, SMBIOSIZE, piix4_driver.name)) {
dev_err(&PIIX4_dev->dev, "Auxiliary SMBus region 0x%x "
"already in use!\n", piix4_smba);
return -EBUSY;
}
dev_info(&PIIX4_dev->dev,
"Auxiliary SMBus Host Controller at 0x%x\n",
piix4_smba);
return piix4_smba;
} }
static int piix4_transaction(void) static int piix4_transaction(struct i2c_adapter *piix4_adapter)
{ {
struct i2c_piix4_adapdata *adapdata = i2c_get_adapdata(piix4_adapter);
unsigned short piix4_smba = adapdata->smba;
int temp; int temp;
int result = 0; int result = 0;
int timeout = 0; int timeout = 0;
dev_dbg(&piix4_adapter.dev, "Transaction (pre): CNT=%02x, CMD=%02x, " dev_dbg(&piix4_adapter->dev, "Transaction (pre): CNT=%02x, CMD=%02x, "
"ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT), "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT),
inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0), inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0),
inb_p(SMBHSTDAT1)); inb_p(SMBHSTDAT1));
/* Make sure the SMBus host is ready to start transmitting */ /* Make sure the SMBus host is ready to start transmitting */
if ((temp = inb_p(SMBHSTSTS)) != 0x00) { if ((temp = inb_p(SMBHSTSTS)) != 0x00) {
dev_dbg(&piix4_adapter.dev, "SMBus busy (%02x). " dev_dbg(&piix4_adapter->dev, "SMBus busy (%02x). "
"Resetting...\n", temp); "Resetting...\n", temp);
outb_p(temp, SMBHSTSTS); outb_p(temp, SMBHSTSTS);
if ((temp = inb_p(SMBHSTSTS)) != 0x00) { if ((temp = inb_p(SMBHSTSTS)) != 0x00) {
dev_err(&piix4_adapter.dev, "Failed! (%02x)\n", temp); dev_err(&piix4_adapter->dev, "Failed! (%02x)\n", temp);
return -EBUSY; return -EBUSY;
} else { } else {
dev_dbg(&piix4_adapter.dev, "Successful!\n"); dev_dbg(&piix4_adapter->dev, "Successful!\n");
} }
} }
...@@ -330,35 +375,35 @@ static int piix4_transaction(void) ...@@ -330,35 +375,35 @@ static int piix4_transaction(void)
/* If the SMBus is still busy, we give up */ /* If the SMBus is still busy, we give up */
if (timeout == MAX_TIMEOUT) { if (timeout == MAX_TIMEOUT) {
dev_err(&piix4_adapter.dev, "SMBus Timeout!\n"); dev_err(&piix4_adapter->dev, "SMBus Timeout!\n");
result = -ETIMEDOUT; result = -ETIMEDOUT;
} }
if (temp & 0x10) { if (temp & 0x10) {
result = -EIO; result = -EIO;
dev_err(&piix4_adapter.dev, "Error: Failed bus transaction\n"); dev_err(&piix4_adapter->dev, "Error: Failed bus transaction\n");
} }
if (temp & 0x08) { if (temp & 0x08) {
result = -EIO; result = -EIO;
dev_dbg(&piix4_adapter.dev, "Bus collision! SMBus may be " dev_dbg(&piix4_adapter->dev, "Bus collision! SMBus may be "
"locked until next hard reset. (sorry!)\n"); "locked until next hard reset. (sorry!)\n");
/* Clock stops and slave is stuck in mid-transmission */ /* Clock stops and slave is stuck in mid-transmission */
} }
if (temp & 0x04) { if (temp & 0x04) {
result = -ENXIO; result = -ENXIO;
dev_dbg(&piix4_adapter.dev, "Error: no response!\n"); dev_dbg(&piix4_adapter->dev, "Error: no response!\n");
} }
if (inb_p(SMBHSTSTS) != 0x00) if (inb_p(SMBHSTSTS) != 0x00)
outb_p(inb(SMBHSTSTS), SMBHSTSTS); outb_p(inb(SMBHSTSTS), SMBHSTSTS);
if ((temp = inb_p(SMBHSTSTS)) != 0x00) { if ((temp = inb_p(SMBHSTSTS)) != 0x00) {
dev_err(&piix4_adapter.dev, "Failed reset at end of " dev_err(&piix4_adapter->dev, "Failed reset at end of "
"transaction (%02x)\n", temp); "transaction (%02x)\n", temp);
} }
dev_dbg(&piix4_adapter.dev, "Transaction (post): CNT=%02x, CMD=%02x, " dev_dbg(&piix4_adapter->dev, "Transaction (post): CNT=%02x, CMD=%02x, "
"ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT), "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT),
inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0), inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0),
inb_p(SMBHSTDAT1)); inb_p(SMBHSTDAT1));
...@@ -370,6 +415,8 @@ static s32 piix4_access(struct i2c_adapter * adap, u16 addr, ...@@ -370,6 +415,8 @@ static s32 piix4_access(struct i2c_adapter * adap, u16 addr,
unsigned short flags, char read_write, unsigned short flags, char read_write,
u8 command, int size, union i2c_smbus_data * data) u8 command, int size, union i2c_smbus_data * data)
{ {
struct i2c_piix4_adapdata *adapdata = i2c_get_adapdata(adap);
unsigned short piix4_smba = adapdata->smba;
int i, len; int i, len;
int status; int status;
...@@ -426,7 +473,7 @@ static s32 piix4_access(struct i2c_adapter * adap, u16 addr, ...@@ -426,7 +473,7 @@ static s32 piix4_access(struct i2c_adapter * adap, u16 addr,
outb_p((size & 0x1C) + (ENABLE_INT9 & 1), SMBHSTCNT); outb_p((size & 0x1C) + (ENABLE_INT9 & 1), SMBHSTCNT);
status = piix4_transaction(); status = piix4_transaction(adap);
if (status) if (status)
return status; return status;
...@@ -466,12 +513,6 @@ static const struct i2c_algorithm smbus_algorithm = { ...@@ -466,12 +513,6 @@ static const struct i2c_algorithm smbus_algorithm = {
.functionality = piix4_func, .functionality = piix4_func,
}; };
static struct i2c_adapter piix4_adapter = {
.owner = THIS_MODULE,
.class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
.algo = &smbus_algorithm,
};
static DEFINE_PCI_DEVICE_TABLE(piix4_ids) = { static DEFINE_PCI_DEVICE_TABLE(piix4_ids) = {
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_3) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_3) },
...@@ -496,6 +537,57 @@ static DEFINE_PCI_DEVICE_TABLE(piix4_ids) = { ...@@ -496,6 +537,57 @@ static DEFINE_PCI_DEVICE_TABLE(piix4_ids) = {
MODULE_DEVICE_TABLE (pci, piix4_ids); MODULE_DEVICE_TABLE (pci, piix4_ids);
static struct i2c_adapter *piix4_main_adapter;
static struct i2c_adapter *piix4_aux_adapter;
static int __devinit piix4_add_adapter(struct pci_dev *dev,
unsigned short smba,
struct i2c_adapter **padap)
{
struct i2c_adapter *adap;
struct i2c_piix4_adapdata *adapdata;
int retval;
adap = kzalloc(sizeof(*adap), GFP_KERNEL);
if (adap == NULL) {
release_region(smba, SMBIOSIZE);
return -ENOMEM;
}
adap->owner = THIS_MODULE;
adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
adap->algo = &smbus_algorithm;
adapdata = kzalloc(sizeof(*adapdata), GFP_KERNEL);
if (adapdata == NULL) {
kfree(adap);
release_region(smba, SMBIOSIZE);
return -ENOMEM;
}
adapdata->smba = smba;
/* set up the sysfs linkage to our parent device */
adap->dev.parent = &dev->dev;
snprintf(adap->name, sizeof(adap->name),
"SMBus PIIX4 adapter at %04x", smba);
i2c_set_adapdata(adap, adapdata);
retval = i2c_add_adapter(adap);
if (retval) {
dev_err(&dev->dev, "Couldn't register adapter!\n");
kfree(adapdata);
kfree(adap);
release_region(smba, SMBIOSIZE);
return retval;
}
*padap = adap;
return 0;
}
static int __devinit piix4_probe(struct pci_dev *dev, static int __devinit piix4_probe(struct pci_dev *dev,
const struct pci_device_id *id) const struct pci_device_id *id)
{ {
...@@ -510,30 +602,52 @@ static int __devinit piix4_probe(struct pci_dev *dev, ...@@ -510,30 +602,52 @@ static int __devinit piix4_probe(struct pci_dev *dev,
else else
retval = piix4_setup(dev, id); retval = piix4_setup(dev, id);
if (retval) /* If no main SMBus found, give up */
if (retval < 0)
return retval; return retval;
/* set up the sysfs linkage to our parent device */ /* Try to register main SMBus adapter, give up if we can't */
piix4_adapter.dev.parent = &dev->dev; retval = piix4_add_adapter(dev, retval, &piix4_main_adapter);
if (retval < 0)
snprintf(piix4_adapter.name, sizeof(piix4_adapter.name), return retval;
"SMBus PIIX4 adapter at %04x", piix4_smba);
if ((retval = i2c_add_adapter(&piix4_adapter))) { /* Check for auxiliary SMBus on some AMD chipsets */
dev_err(&dev->dev, "Couldn't register adapter!\n"); if (dev->vendor == PCI_VENDOR_ID_ATI &&
release_region(piix4_smba, SMBIOSIZE); dev->device == PCI_DEVICE_ID_ATI_SBX00_SMBUS &&
piix4_smba = 0; dev->revision < 0x40) {
retval = piix4_setup_aux(dev, id, 0x58);
if (retval > 0) {
/* Try to add the aux adapter if it exists,
* piix4_add_adapter will clean up if this fails */
piix4_add_adapter(dev, retval, &piix4_aux_adapter);
}
} }
return retval; return 0;
}
static void __devexit piix4_adap_remove(struct i2c_adapter *adap)
{
struct i2c_piix4_adapdata *adapdata = i2c_get_adapdata(adap);
if (adapdata->smba) {
i2c_del_adapter(adap);
release_region(adapdata->smba, SMBIOSIZE);
kfree(adapdata);
kfree(adap);
}
} }
static void __devexit piix4_remove(struct pci_dev *dev) static void __devexit piix4_remove(struct pci_dev *dev)
{ {
if (piix4_smba) { if (piix4_main_adapter) {
i2c_del_adapter(&piix4_adapter); piix4_adap_remove(piix4_main_adapter);
release_region(piix4_smba, SMBIOSIZE); piix4_main_adapter = NULL;
piix4_smba = 0; }
if (piix4_aux_adapter) {
piix4_adap_remove(piix4_aux_adapter);
piix4_aux_adapter = NULL;
} }
} }
...@@ -544,20 +658,9 @@ static struct pci_driver piix4_driver = { ...@@ -544,20 +658,9 @@ static struct pci_driver piix4_driver = {
.remove = __devexit_p(piix4_remove), .remove = __devexit_p(piix4_remove),
}; };
static int __init i2c_piix4_init(void) module_pci_driver(piix4_driver);
{
return pci_register_driver(&piix4_driver);
}
static void __exit i2c_piix4_exit(void)
{
pci_unregister_driver(&piix4_driver);
}
MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl> and " MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl> and "
"Philip Edelbrock <phil@netroedge.com>"); "Philip Edelbrock <phil@netroedge.com>");
MODULE_DESCRIPTION("PIIX4 SMBus driver"); MODULE_DESCRIPTION("PIIX4 SMBus driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
module_init(i2c_piix4_init);
module_exit(i2c_piix4_exit);
...@@ -163,17 +163,7 @@ static struct pci_driver ce4100_i2c_driver = { ...@@ -163,17 +163,7 @@ static struct pci_driver ce4100_i2c_driver = {
.remove = __devexit_p(ce4100_i2c_remove), .remove = __devexit_p(ce4100_i2c_remove),
}; };
static int __init ce4100_i2c_init(void) module_pci_driver(ce4100_i2c_driver);
{
return pci_register_driver(&ce4100_i2c_driver);
}
module_init(ce4100_i2c_init);
static void __exit ce4100_i2c_exit(void)
{
pci_unregister_driver(&ce4100_i2c_driver);
}
module_exit(ce4100_i2c_exit);
MODULE_DESCRIPTION("CE4100 PCI-I2C glue code for PXA's driver"); MODULE_DESCRIPTION("CE4100 PCI-I2C glue code for PXA's driver");
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");
......
...@@ -513,21 +513,8 @@ static struct pci_driver sis630_driver = { ...@@ -513,21 +513,8 @@ static struct pci_driver sis630_driver = {
.remove = __devexit_p(sis630_remove), .remove = __devexit_p(sis630_remove),
}; };
static int __init i2c_sis630_init(void) module_pci_driver(sis630_driver);
{
return pci_register_driver(&sis630_driver);
}
static void __exit i2c_sis630_exit(void)
{
pci_unregister_driver(&sis630_driver);
}
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_AUTHOR("Alexander Malysh <amalysh@web.de>"); MODULE_AUTHOR("Alexander Malysh <amalysh@web.de>");
MODULE_DESCRIPTION("SIS630 SMBus driver"); MODULE_DESCRIPTION("SIS630 SMBus driver");
module_init(i2c_sis630_init);
module_exit(i2c_sis630_exit);
...@@ -324,21 +324,8 @@ static struct pci_driver sis96x_driver = { ...@@ -324,21 +324,8 @@ static struct pci_driver sis96x_driver = {
.remove = __devexit_p(sis96x_remove), .remove = __devexit_p(sis96x_remove),
}; };
static int __init i2c_sis96x_init(void) module_pci_driver(sis96x_driver);
{
return pci_register_driver(&sis96x_driver);
}
static void __exit i2c_sis96x_exit(void)
{
pci_unregister_driver(&sis96x_driver);
}
MODULE_AUTHOR("Mark M. Hoffman <mhoffman@lightlink.com>"); MODULE_AUTHOR("Mark M. Hoffman <mhoffman@lightlink.com>");
MODULE_DESCRIPTION("SiS96x SMBus driver"); MODULE_DESCRIPTION("SiS96x SMBus driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
/* Register initialization functions using helper macros */
module_init(i2c_sis96x_init);
module_exit(i2c_sis96x_exit);
...@@ -143,6 +143,7 @@ static const struct i2c_algorithm usb_algorithm = { ...@@ -143,6 +143,7 @@ static const struct i2c_algorithm usb_algorithm = {
static const struct usb_device_id i2c_tiny_usb_table[] = { static const struct usb_device_id i2c_tiny_usb_table[] = {
{ USB_DEVICE(0x0403, 0xc631) }, /* FTDI */ { USB_DEVICE(0x0403, 0xc631) }, /* FTDI */
{ USB_DEVICE(0x1c40, 0x0534) }, /* EZPrototypes */ { USB_DEVICE(0x1c40, 0x0534) }, /* EZPrototypes */
{ USB_DEVICE(0x1964, 0x0001) }, /* Robofuzz OSIF */
{ } /* Terminating entry */ { } /* Terminating entry */
}; };
......
...@@ -161,20 +161,8 @@ static struct pci_driver vt586b_driver = { ...@@ -161,20 +161,8 @@ static struct pci_driver vt586b_driver = {
.remove = __devexit_p(vt586b_remove), .remove = __devexit_p(vt586b_remove),
}; };
static int __init i2c_vt586b_init(void) module_pci_driver(vt586b_driver);
{
return pci_register_driver(&vt586b_driver);
}
static void __exit i2c_vt586b_exit(void)
{
pci_unregister_driver(&vt586b_driver);
}
MODULE_AUTHOR("Kyösti Mälkki <kmalkki@cc.hut.fi>"); MODULE_AUTHOR("Kyösti Mälkki <kmalkki@cc.hut.fi>");
MODULE_DESCRIPTION("i2c for Via vt82c586b southbridge"); MODULE_DESCRIPTION("i2c for Via vt82c586b southbridge");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
module_init(i2c_vt586b_init);
module_exit(i2c_vt586b_exit);
...@@ -2122,7 +2122,7 @@ s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags, ...@@ -2122,7 +2122,7 @@ s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags,
int try; int try;
s32 res; s32 res;
flags &= I2C_M_TEN | I2C_CLIENT_PEC; flags &= I2C_M_TEN | I2C_CLIENT_PEC | I2C_CLIENT_SCCB;
if (adapter->algo->smbus_xfer) { if (adapter->algo->smbus_xfer) {
i2c_lock_adapter(adapter); i2c_lock_adapter(adapter);
...@@ -2140,11 +2140,17 @@ s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags, ...@@ -2140,11 +2140,17 @@ s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags,
break; break;
} }
i2c_unlock_adapter(adapter); i2c_unlock_adapter(adapter);
} else
res = i2c_smbus_xfer_emulated(adapter, addr, flags, read_write,
command, protocol, data);
return res; if (res != -EOPNOTSUPP || !adapter->algo->master_xfer)
return res;
/*
* Fall back to i2c_smbus_xfer_emulated if the adapter doesn't
* implement native support for the SMBus operation.
*/
}
return i2c_smbus_xfer_emulated(adapter, addr, flags, read_write,
command, protocol, data);
} }
EXPORT_SYMBOL(i2c_smbus_xfer); EXPORT_SYMBOL(i2c_smbus_xfer);
......
...@@ -245,18 +245,7 @@ int i2c_handle_smbus_alert(struct i2c_client *ara) ...@@ -245,18 +245,7 @@ int i2c_handle_smbus_alert(struct i2c_client *ara)
} }
EXPORT_SYMBOL_GPL(i2c_handle_smbus_alert); EXPORT_SYMBOL_GPL(i2c_handle_smbus_alert);
static int __init i2c_smbus_init(void) module_i2c_driver(smbalert_driver);
{
return i2c_add_driver(&smbalert_driver);
}
static void __exit i2c_smbus_exit(void)
{
i2c_del_driver(&smbalert_driver);
}
module_init(i2c_smbus_init);
module_exit(i2c_smbus_exit);
MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>"); MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
MODULE_DESCRIPTION("SMBus protocol extensions support"); MODULE_DESCRIPTION("SMBus protocol extensions support");
......
...@@ -396,6 +396,6 @@ static struct i2c_driver pca9541_driver = { ...@@ -396,6 +396,6 @@ static struct i2c_driver pca9541_driver = {
module_i2c_driver(pca9541_driver); module_i2c_driver(pca9541_driver);
MODULE_AUTHOR("Guenter Roeck <guenter.roeck@ericsson.com>"); MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
MODULE_DESCRIPTION("PCA9541 I2C master selector driver"); MODULE_DESCRIPTION("PCA9541 I2C master selector driver");
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");
...@@ -25,11 +25,6 @@ ...@@ -25,11 +25,6 @@
#define I2C_DRIVERID_WIS_TW2804 0xf0f6 #define I2C_DRIVERID_WIS_TW2804 0xf0f6
#define I2C_DRIVERID_S2250 0xf0f7 #define I2C_DRIVERID_S2250 0xf0f7
/* Flag to indicate that the client needs to be accessed with SCCB semantics */
/* We re-use the I2C_M_TEN value so the flag passes through the masks in the
* core I2C code. Major kludge, but the I2C layer ain't exactly flexible. */
#define I2C_CLIENT_SCCB 0x10
/* Definitions for new video decoder commands */ /* Definitions for new video decoder commands */
struct video_decoder_resolution { struct video_decoder_resolution {
......
...@@ -425,6 +425,8 @@ void i2c_unlock_adapter(struct i2c_adapter *); ...@@ -425,6 +425,8 @@ void i2c_unlock_adapter(struct i2c_adapter *);
#define I2C_CLIENT_TEN 0x10 /* we have a ten bit chip address */ #define I2C_CLIENT_TEN 0x10 /* we have a ten bit chip address */
/* Must equal I2C_M_TEN below */ /* Must equal I2C_M_TEN below */
#define I2C_CLIENT_WAKE 0x80 /* for board_info; true iff can wake */ #define I2C_CLIENT_WAKE 0x80 /* for board_info; true iff can wake */
#define I2C_CLIENT_SCCB 0x9000 /* Use Omnivision SCCB protocol */
/* Must match I2C_M_STOP|IGNORE_NAK */
/* i2c adapter classes (bitmask) */ /* i2c adapter classes (bitmask) */
#define I2C_CLASS_HWMON (1<<0) /* lm_sensors, ... */ #define I2C_CLASS_HWMON (1<<0) /* lm_sensors, ... */
...@@ -541,6 +543,7 @@ struct i2c_msg { ...@@ -541,6 +543,7 @@ struct i2c_msg {
__u16 flags; __u16 flags;
#define I2C_M_TEN 0x0010 /* this is a ten bit chip address */ #define I2C_M_TEN 0x0010 /* this is a ten bit chip address */
#define I2C_M_RD 0x0001 /* read data, from slave to master */ #define I2C_M_RD 0x0001 /* read data, from slave to master */
#define I2C_M_STOP 0x8000 /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_NOSTART 0x4000 /* if I2C_FUNC_NOSTART */ #define I2C_M_NOSTART 0x4000 /* if I2C_FUNC_NOSTART */
#define I2C_M_REV_DIR_ADDR 0x2000 /* if I2C_FUNC_PROTOCOL_MANGLING */ #define I2C_M_REV_DIR_ADDR 0x2000 /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_IGNORE_NAK 0x1000 /* if I2C_FUNC_PROTOCOL_MANGLING */ #define I2C_M_IGNORE_NAK 0x1000 /* if I2C_FUNC_PROTOCOL_MANGLING */
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册