[PATCH 3/3] i2c-piix4: support aux SMBus on AMD chipsets

From: Andrew Armenia
Date: Mon Jun 04 2012 - 21:49:29 EST


Some AMD chipsets, such as the SP5100, have an auxiliary SMBus with a second
set of registers. This patch adds support for the SP5100 and should work on
similar chipsets. Tested on ASUS KCMA-D8 motherboard.

Signed-off-by: Andrew Armenia <andrew@xxxxxxxxxxxxxxxx>
---
drivers/i2c/busses/i2c-piix4.c | 83 ++++++++++++++++++++++++++++++++++++----
1 file changed, 76 insertions(+), 7 deletions(-)

diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c
index 8a87b3f..972b604 100644
--- a/drivers/i2c/busses/i2c-piix4.c
+++ b/drivers/i2c/busses/i2c-piix4.c
@@ -25,7 +25,8 @@
AMD Hudson-2
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 two SMBus
+ interfaces.
*/

#include <linux/module.h>
@@ -66,6 +67,7 @@
#define SMBSHDW1 0x0D4
#define SMBSHDW2 0x0D5
#define SMBREV 0x0D6
+#define SMBAUXBA 0x058

/* Other settings */
#define MAX_TIMEOUT 500
@@ -130,6 +132,8 @@ struct i2c_piix4_adapdata {
unsigned short smba;
};

+static void piix4_adap_remove(struct i2c_adapter *adap);
+
static int __devinit piix4_setup(struct pci_dev *PIIX4_dev,
const struct pci_device_id *id,
unsigned short *smba)
@@ -300,6 +304,45 @@ static int __devinit piix4_setup_sb800(struct pci_dev *PIIX4_dev,
return 0;
}

+static int __devinit piix4_setup_aux(struct pci_dev *PIIX4_dev,
+ const struct pci_device_id *id,
+ unsigned short base_reg_addr,
+ unsigned short *smba)
+{
+ /* Set up auxiliary SMBus controllers found on some AMD
+ * chipsets e.g. SP5100 */
+ unsigned short piix4_smba;
+
+ /* Read address of auxiliary SMBus controller */
+ pci_read_config_word(PIIX4_dev, base_reg_addr, &piix4_smba);
+ piix4_smba &= 0xffe0;
+
+ if (piix4_smba == 0) {
+ dev_err(&PIIX4_dev->dev, "Aux SMBus base address "
+ "uninitialized - upgrade BIOS\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, "Aux 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
+ );
+
+ *smba = piix4_smba;
+
+ return 0;
+}
+
+
static int piix4_transaction(unsigned short piix4_smba)
{
int temp;
@@ -505,6 +548,7 @@ static DEFINE_PCI_DEVICE_TABLE(piix4_ids) = {
MODULE_DEVICE_TABLE (pci, piix4_ids);

static struct i2c_adapter *piix4_main_adapter;
+static struct i2c_adapter *piix4_aux_adapter;

/* register piix4 I2C adapter at the given base address */
static int piix4_add_adapter(struct pci_dev *dev, unsigned short smba,
@@ -562,9 +606,33 @@ static int __devinit piix4_probe(struct pci_dev *dev,
retval = piix4_setup(dev, id, &smba);

if (retval)
- return retval;
+ goto error;
+
+ retval = piix4_add_adapter(dev, smba, &piix4_main_adapter);
+ if (retval)
+ goto error;

- return piix4_add_adapter(dev, smba, &piix4_main_adapter);
+ /* check for AMD SP5100 (maybe others) with aux SMBus port */
+ if (dev->vendor == PCI_VENDOR_ID_ATI &&
+ dev->device == PCI_DEVICE_ID_ATI_SBX00_SMBUS &&
+ dev->revision == 0x3d) {
+
+ retval = piix4_setup_aux(dev, id, SMBAUXBA, &smba);
+ if (retval)
+ goto error;
+
+ retval = piix4_add_adapter(dev, smba, &piix4_aux_adapter);
+ if (retval)
+ goto error;
+ }
+
+ return 0;
+
+error:
+ /* clean up any adapters that were already added */
+ piix4_adap_remove(piix4_main_adapter);
+ piix4_adap_remove(piix4_aux_adapter);
+ return retval;
}

/* Remove the adapter and its associated IO region */
@@ -572,6 +640,9 @@ static void piix4_adap_remove(struct i2c_adapter *adap)
{
struct i2c_piix4_adapdata *adapdata;

+ if (adap == NULL)
+ return;
+
adapdata = (struct i2c_piix4_adapdata *)i2c_get_adapdata(adap);
if (adapdata->smba) {
i2c_del_adapter(adap);
@@ -585,10 +656,8 @@ static void piix4_adap_remove(struct i2c_adapter *adap)

static void __devexit piix4_remove(struct pci_dev *dev)
{
- if (piix4_main_adapter) {
- piix4_adap_remove(piix4_main_adapter);
- piix4_main_adapter = NULL;
- }
+ piix4_adap_remove(piix4_main_adapter);
+ piix4_adap_remove(piix4_aux_adapter);
}

static struct pci_driver piix4_driver = {
--
1.7.10

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/