Dear list, thanks for your instructions. I slightly modified the driver so that it builds on 3.13-rc4. I can confirm that it works well. I also talked to the company (www.men.de) that released the original patch and they would love to get it into the kernel. Please find attached the patch to i2c-piix4.c of 3.13-rc4. I also prepared a .tgz that contains - the original archive from men.de - my modified driver - the patch itself The .tgz can be obtained from http://daduke.org/junk/piix4.tgz thanks again and Happy Holidays, -Christian On Tue, Dec 17, 2013 at 07:10:53PM +0100, Wolfram Sang wrote: > > > > I'm currently beta testing a pretty cool embedded board for router > > > applications etc. (http://www.pcengines.ch/apu.htm) that sports a Hudson-1 FCH > > > which is pretty similar to the Hudson-2 your module supports but sufficiently > > > different so that i2c-piix4 doesn't work. > > > I found a patched i2c-piix4 source that adds support for the Hudson-1 and it > > > works beautifully: http://www.men.de/products/13SC24-90.html#t=overview > > > Now I'm wondering if you would be willing to get this patch into lm-sensors > > > and also the kernel. > > > If there's anything I can do to help, please let me know. > > Can't say anything about the patch since it requires registration to get > it :( > > What you/someone can do: > > * get the patch > * port it to a recent kernel and verify it still works > * read Documentation/SubmittingPatches > * send the patch > > Regards, > > Wolfram > #------------------------------------- PATCH ------------# --- i2c-piix4.c 2013-12-20 14:22:26.000000000 +0100 +++ i2c-piix4.c.orig 2013-12-15 21:31:33.000000000 +0100 @@ -1,40 +1,3 @@ -/********************* P r o g r a m - M o d u l e ***********************/ -/*! - * \file i2c-piix4.c - * - * \author aw - * $Date: 2012/12/03 10:44:30 $ - * $Revision: 1.1 $ - * - * \brief I2C Driver support for SC 24 SMBus. Derived from original - * i2c-piix4.c and enhanced to support 2nd SMBus controller - * on 08SC24. - * - * Note: 1st Controller shall be IO-Mapped - * 2nd Controller IO-Mapped or MEM-Mapped - * - * Switches: - */ -/*---------------------------[ Public Functions ]---------------------------- - * - *-------------------------------[ History ]--------------------------------- - * - * $Log: i2c-piix4.c,v $ - * Revision 1.1 2012/12/03 10:44:30 awerner - * Initial Revision - * - * - * - *--------------------------------------------------------------------------- - * (c) Copyright 2012 by MEN mikro elektronik GmbH, Nuremberg, Germany - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - ****************************************************************************/ - - /* Copyright (c) 1998 - 2002 Frodo Looijaard <frodol@xxxxxx> and Philip Edelbrock <phil@xxxxxxxxxxxxx> @@ -52,18 +15,19 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ +*/ /* Supports: Intel PIIX4, 440MX Serverworks OSB4, CSB5, CSB6, HT-1000, HT-1100 - ATI IXP200, IXP300, IXP400, SB600, SB700, SB800 - AMD Hudson-2 + ATI IXP200, IXP300, IXP400, SB600, SB700/SP5100, SB800 + AMD Hudson-2, CZ 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/moduleparam.h> @@ -73,40 +37,29 @@ #include <linux/stddef.h> #include <linux/ioport.h> #include <linux/i2c.h> +#include <linux/slab.h> #include <linux/init.h> #include <linux/dmi.h> #include <linux/acpi.h> #include <linux/io.h> -#include <linux/mutex.h> -/* - * DEFINES - */ -/* PIIX4 SMBus adress offset Makros */ -#define SMBHSTSTS 0 -#define SMBHSLVSTS 1 -#define SMBHSTCNT 2 -#define SMBHSTCMD 3 -#define SMBHSTADD 4 -#define SMBHSTDAT0 5 -#define SMBHSTDAT1 6 -#define SMBBLKDAT 7 -#define SMBSLVCNT 8 -#define SMBSHDWCMD 9 -#define SMBSLVEVT 0xA -#define SMBSLVDAT 0xC +/* PIIX4 SMBus address offsets */ +#define SMBHSTSTS (0 + piix4_smba) +#define SMBHSLVSTS (1 + piix4_smba) +#define SMBHSTCNT (2 + piix4_smba) +#define SMBHSTCMD (3 + piix4_smba) +#define SMBHSTADD (4 + piix4_smba) +#define SMBHSTDAT0 (5 + piix4_smba) +#define SMBHSTDAT1 (6 + piix4_smba) +#define SMBBLKDAT (7 + piix4_smba) +#define SMBSLVCNT (8 + piix4_smba) +#define SMBSHDWCMD (9 + piix4_smba) +#define SMBSLVEVT (0xA + piix4_smba) +#define SMBSLVDAT (0xC + piix4_smba) /* count for request_region */ -#define SMBIOSIZE 8 /* IO-mapped 1st SMBus */ -#define SMBMSIZE 8 /* Memory-mapped 2nd SMBus */ - -#define ACPIMMIOEN_ENBL 0x00000001 -#define ACPIMMIOEN_SEL 0x00000002 - -/* Mapping of SMBus 1 Controller */ -#define MEMMAP 0 -#define IOMAP 1 +#define SMBIOSIZE 8 /* PCI Address Constants */ #define SMBBA 0x090 @@ -116,9 +69,6 @@ #define SMBSHDW2 0x0D5 #define SMBREV 0x0D6 -/* primary controller IO mapped addresses */ -#define SMB_ADDR_INDEX 0xcd6 - /* Other settings */ #define MAX_TIMEOUT 500 #define ENABLE_INT9 0 @@ -146,70 +96,10 @@ MODULE_PARM_DESC(force_addr, "Forcibly enable the PIIX4 at the given address. " "EXTREMELY DANGEROUS!"); - -/* - * GLOBALES - */ - -/* SMBus base adress Controller 0 */ -static unsigned short piix4_smba0; -/* SMBus base adress Controller 1 */ -static unsigned int piix4_smba1; - static int srvrworks_csb5_delay; static struct pci_driver piix4_driver; -static struct i2c_adapter piix4_adapter0; -static struct i2c_adapter piix4_adapter1; -static struct i2c_adapter piix4_adapter2; - -static u8 SMBusMap; - -/* virtual adress 2nd SMBus Controller */ -static void *virt_addr; - - -/* mutex to lock the transaction functions, - * because it could be that both Controller/adapter access - * the function at the same time.*/ -static struct mutex funcLock; - -/************************************************************************/ -/** request IO or mem mapped memory - * - * \param from \IN start address to release - * \param length \IN length of data to release - * \param spacetype \IN 0 = memory 1 = IO. Type of requested memory - * - * \return \c 0 On success or error code - */ -struct resource *reqAdressSpace(unsigned long from, unsigned long length, - const char* name, u8 spacetype) { - if (spacetype == MEMMAP) - return request_mem_region(from, length, name); - - else - return request_region(from, length, name); -} - - -/************************************************************************/ -/** free requested memory, IO or mem mapped - * - * \param from \IN start address to release - * \param length \IN length of data to release - * \param spacetype \IN 0 = memory 1 = IO. Type of requested memory - * - * \return \c 0 On success or error code - */ -void relAdressSpace(unsigned long from, unsigned long length, u8 spacetype) { - if (spacetype == MEMMAP) - release_mem_region(from, length); - else - release_region(from, length); -} - -static struct dmi_system_id piix4_dmi_blacklist[] = { +static const struct dmi_system_id piix4_dmi_blacklist[] = { { .ident = "Sapphire AM2RD790", .matches = { @@ -224,32 +114,28 @@ static struct dmi_system_id piix4_dmi_bl DMI_MATCH(DMI_BOARD_NAME, "LP UT 790FX"), }, }, - {} + { } }; /* The IBM entry is in a separate table because we only check it on Intel-based systems */ -static struct dmi_system_id piix4_dmi_ibm[] = { +static const struct dmi_system_id piix4_dmi_ibm[] = { { .ident = "IBM", - .matches = {DMI_MATCH(DMI_SYS_VENDOR, "IBM"),}, + .matches = { DMI_MATCH(DMI_SYS_VENDOR, "IBM"), }, }, - {}, + { }, }; +struct i2c_piix4_adapdata { + unsigned short smba; +}; -/************************************************************************/ -/** SMB controller setup function called upon module init - * - * \param *PIIX4_dev \IN PCI device struct - * \param *id \IN PCI device ID - * - * \return \c 0 On success or error code - */ static int piix4_setup(struct pci_dev *PIIX4_dev, const struct pci_device_id *id) { unsigned char temp; + unsigned short piix4_smba; if ((PIIX4_dev->vendor == PCI_VENDOR_ID_SERVERWORKS) && (PIIX4_dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5)) @@ -274,12 +160,12 @@ static int piix4_setup(struct pci_dev *P /* Determine the address of the SMBus areas */ if (force_addr) { - piix4_smba0 = force_addr & 0xfff0; + piix4_smba = force_addr & 0xfff0; force = 0; } else { - pci_read_config_word(PIIX4_dev, SMBBA, &piix4_smba0); - piix4_smba0 &= 0xfff0; - if(piix4_smba0 == 0) { + pci_read_config_word(PIIX4_dev, SMBBA, &piix4_smba); + piix4_smba &= 0xfff0; + if(piix4_smba == 0) { dev_err(&PIIX4_dev->dev, "SMBus base address " "uninitialized - upgrade BIOS or use " "force_addr=0xaddr\n"); @@ -287,12 +173,12 @@ static int piix4_setup(struct pci_dev *P } } - if (acpi_check_region(piix4_smba0, SMBIOSIZE, piix4_driver.name)) + if (acpi_check_region(piix4_smba, SMBIOSIZE, piix4_driver.name)) return -ENODEV; - if (!request_region(piix4_smba0, SMBIOSIZE, piix4_driver.name)) { + if (!request_region(piix4_smba, SMBIOSIZE, piix4_driver.name)) { dev_err(&PIIX4_dev->dev, "SMBus region 0x%x already in use!\n", - piix4_smba0); + piix4_smba); return -EBUSY; } @@ -302,10 +188,10 @@ static int piix4_setup(struct pci_dev *P sure, we disable the PIIX4 first. */ if (force_addr) { pci_write_config_byte(PIIX4_dev, SMBHSTCFG, temp & 0xfe); - pci_write_config_word(PIIX4_dev, SMBBA, piix4_smba0); + pci_write_config_word(PIIX4_dev, SMBBA, piix4_smba); pci_write_config_byte(PIIX4_dev, SMBHSTCFG, temp | 0x01); dev_info(&PIIX4_dev->dev, "WARNING: SMBus interface set to " - "new address %04x!\n", piix4_smba0); + "new address %04x!\n", piix4_smba); } else if ((temp & 1) == 0) { if (force) { /* This should never need to be done, but has been @@ -318,14 +204,12 @@ static int piix4_setup(struct pci_dev *P */ pci_write_config_byte(PIIX4_dev, SMBHSTCFG, temp | 1); - dev_printk(KERN_NOTICE, &PIIX4_dev->dev, - "WARNING: SMBus interface has been " - "FORCEFULLY ENABLED!\n"); + dev_notice(&PIIX4_dev->dev, + "WARNING: SMBus interface has been FORCEFULLY ENABLED!\n"); } else { dev_err(&PIIX4_dev->dev, "Host SMBus controller not enabled!\n"); - release_region(piix4_smba0, SMBIOSIZE); - piix4_smba0 = 0; + release_region(piix4_smba, SMBIOSIZE); return -ENODEV; } } @@ -341,30 +225,17 @@ static int piix4_setup(struct pci_dev *P pci_read_config_byte(PIIX4_dev, SMBREV, &temp); dev_info(&PIIX4_dev->dev, "SMBus Host Controller at 0x%x, revision %d\n", - piix4_smba0, temp); + piix4_smba, temp); - return 0; + return piix4_smba; } -/************************************************************************/ -/** setup primary sb800 SMB controller - * - * This Function determine the base adress of the 2nd Controller [SMBus 1]. - * There is also a query if the controller is enabled, and a query if - * if the Controller is IO or Memory mapped. - * If the controller is memory mapped, the function will get a virtuell - * adress to work with. - * - * \param *PIIX4_dev \IN i2c pci main device Handle - * \param *id \IN i2c pci main device ID - * - * \return \c 0 On success or error code - */ static int piix4_setup_sb800(struct pci_dev *PIIX4_dev, - const struct pci_device_id *id) + const struct pci_device_id *id, u8 aux) { - unsigned short smba_idx = SMB_ADDR_INDEX; - u8 smba_en_lo, smba_en_hi, i2ccfg, i2ccfg_offset = 0x10, smb_en = 0x2c; + unsigned short piix4_smba; + unsigned short smba_idx = 0xcd6; + u8 smba_en_lo, smba_en_hi, i2ccfg, i2ccfg_offset = 0x10, smb_en; /* SB800 and later SMBus does not support forcing address */ if (force || force_addr) { @@ -374,6 +245,8 @@ static int piix4_setup_sb800(struct pci_ } /* Determine the address of the SMBus areas */ + smb_en = (aux) ? 0x28 : 0x2c; + if (!request_region(smba_idx, 2, "smba_idx")) { dev_err(&PIIX4_dev->dev, "SMBus base address index region " "0x%x already in use!\n", smba_idx); @@ -385,34 +258,38 @@ static int piix4_setup_sb800(struct pci_ smba_en_hi = inb_p(smba_idx + 1); release_region(smba_idx, 2); - /* check if the SMBus is enabled */ if ((smba_en_lo & 1) == 0) { dev_err(&PIIX4_dev->dev, "Host SMBus controller not enabled!\n"); return -ENODEV; } - piix4_smba0 = ((smba_en_hi << 8) | smba_en_lo) & 0xffe0; - if (acpi_check_region(piix4_smba0, SMBIOSIZE, piix4_driver.name)) + piix4_smba = ((smba_en_hi << 8) | smba_en_lo) & 0xffe0; + if (acpi_check_region(piix4_smba, SMBIOSIZE, piix4_driver.name)) return -ENODEV; - if (!request_region(piix4_smba0, SMBIOSIZE, piix4_driver.name)) { + if (!request_region(piix4_smba, SMBIOSIZE, piix4_driver.name)) { dev_err(&PIIX4_dev->dev, "SMBus region 0x%x already in use!\n", - piix4_smba0); + piix4_smba); return -EBUSY; } + /* Aux SMBus does not support IRQ information */ + if (aux) { + dev_info(&PIIX4_dev->dev, + "SMBus Host Controller at 0x%x\n", piix4_smba); + return piix4_smba; + } + /* Request the SMBus I2C bus config region */ - if (!request_region(piix4_smba0 + i2ccfg_offset, 1, "i2ccfg")) { + if (!request_region(piix4_smba + i2ccfg_offset, 1, "i2ccfg")) { dev_err(&PIIX4_dev->dev, "SMBus I2C bus config region " - "0x%x already in use!\n", piix4_smba0 + i2ccfg_offset); - release_region(piix4_smba0, SMBIOSIZE); - piix4_smba0 = 0; + "0x%x already in use!\n", piix4_smba + i2ccfg_offset); + release_region(piix4_smba, SMBIOSIZE); return -EBUSY; } - - i2ccfg = inb_p(piix4_smba0 + i2ccfg_offset); - release_region(piix4_smba0 + i2ccfg_offset, 1); + i2ccfg = inb_p(piix4_smba + i2ccfg_offset); + release_region(piix4_smba + i2ccfg_offset, 1); if (i2ccfg & 1) dev_dbg(&PIIX4_dev->dev, "Using IRQ for SMBus.\n"); @@ -421,117 +298,70 @@ static int piix4_setup_sb800(struct pci_ dev_info(&PIIX4_dev->dev, "SMBus Host Controller at 0x%x, revision %d\n", - piix4_smba0, i2ccfg >> 4); + piix4_smba, i2ccfg >> 4); - return 0; + return piix4_smba; } - -/************************************************************************/ -/** setup secondary sb800 SMB controller - * - * This Function determine the base adress of the 2nd Controller [SMBus 1]. - * There is also a query if the controller is enabled, and a query if - * if the Controller is IO or Memory mapped. - * If the controller is memory mapped, the function will get a virtuell - * adress to work with. - * - * \param *PIIX4_dev \IN i2c pci main device Handle - * \param *id \IN i2c pci main device ID - * - * \return \c 0 On success or error code - */ -static int sec_piix4_setup_sb800(struct pci_dev *PIIX4_dev, - const struct pci_device_id *id) +static int piix4_setup_aux(struct pci_dev *PIIX4_dev, + const struct pci_device_id *id, + unsigned short base_reg_addr) { - unsigned short smba_idx = SMB_ADDR_INDEX; - unsigned int i; - u8 smb_en = 0x24; + /* Set up auxiliary SMBus controllers found on some + * AMD chipsets e.g. SP5100 (SB700 derivative) */ - /* SB800 and later SMBus does not support forcing address */ - if (force || force_addr) { - dev_err(&PIIX4_dev->dev, "SMBus does not support " - "forcing address!\n"); - return -EINVAL; - } - - /* Determine the address of the 2nd SMBus Controller */ - if (!request_region(smba_idx, 4, "smba_idx")) { - dev_err(&PIIX4_dev->dev, "SMBus base address index region " - "0x%x already in use!\n", smba_idx); - return -EBUSY; - } + unsigned short piix4_smba; - /* retrieve mem mapped address of 2nd controller */ - for (i=0; i<4; i++) { - /* write indirect index of Address...*/ - outb_p(smb_en+i, smba_idx); - /* and read address bytes, 4 times */ - piix4_smba1 |=(inb_p(smba_idx+1)) << (i*8); + /* 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; } - release_region(smba_idx, 4); - - /* check if 2nd controller is ENABLED */ - if( !(piix4_smba1 & ACPIMMIOEN_ENBL) ) { - dev_err(&PIIX4_dev->dev, - "Host SMBus1 2nd controller not enabled!\n"); + piix4_smba &= 0xfff0; + if (piix4_smba == 0) { + dev_dbg(&PIIX4_dev->dev, + "Auxiliary SMBus base address uninitialized\n"); return -ENODEV; } - /* Check if the 2nd Controller is MEM-mapped or IO-mapped */ - /* New Functions to Request and Release Space Areas "reqAdressSpace() and relAdressSpace()" */ - /* to differ between request_mem_region and request_region */ - if( piix4_smba1 & ACPIMMIOEN_SEL ) - SMBusMap = IOMAP; - else - SMBusMap = MEMMAP; - - /* adress mask + 0x900 Offset for the ASF-Registers */ - piix4_smba1 = ( piix4_smba1 & 0xFFFFF000 ) + 0x900; + if (acpi_check_region(piix4_smba, SMBIOSIZE, piix4_driver.name)) + return -ENODEV; - /* Request space region of 2nd Controller SMBus 1 */ - if ( !reqAdressSpace(piix4_smba1, SMBMSIZE, "piix4_I2C_2nd_Controller",SMBusMap) ) { - dev_err(&PIIX4_dev->dev, "SMBus region 0x%x already in use!\n", - piix4_smba1); + 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; } - /* printk("MEN: Address of 2nd I2C controller = 0x%08x\n", piix4_smba1); */ - - /* memory mapping 2nd SMBus Controller */ - if(SMBusMap == MEMMAP) - virt_addr = ioremap(piix4_smba1,SMBMSIZE); + dev_info(&PIIX4_dev->dev, + "Auxiliary SMBus Host Controller at 0x%x\n", + piix4_smba); - return 0; + return piix4_smba; } - -/************************************************************************/ -/** Transaction function for both Controllers, IO-mapped - * - * \param SMBusaddr \IN adress of SMBus Controller - * \param i2c_adapter \IN adapter which comes from the i2c_access function - * - * \return \c 0 On success or error code - */ - -static int piix4_transaction_io(unsigned int SMBusddr,struct i2c_adapter *piix4_adapter) +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 result = 0; int timeout = 0; dev_dbg(&piix4_adapter->dev, "Transaction (pre): CNT=%02x, CMD=%02x, " - "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBusddr + SMBHSTCNT), - inb_p(SMBusddr + SMBHSTCMD), inb_p(SMBusddr + SMBHSTADD), - inb_p(SMBusddr + SMBHSTDAT0), inb_p(SMBusddr + SMBHSTDAT1)); + "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT), + inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0), + inb_p(SMBHSTDAT1)); /* Make sure the SMBus host is ready to start transmitting */ - if ((temp = inb_p(SMBusddr + SMBHSTSTS)) != 0x00) { - dev_dbg(&piix4_adapter->dev, "SMBus busy (%02x). Resetting...\n", temp); - outb_p(temp, SMBusddr + SMBHSTSTS); - if ((temp = inb_p(SMBusddr + SMBHSTSTS)) != 0x00) { + if ((temp = inb_p(SMBHSTSTS)) != 0x00) { + dev_dbg(&piix4_adapter->dev, "SMBus busy (%02x). " + "Resetting...\n", temp); + outb_p(temp, SMBHSTSTS); + if ((temp = inb_p(SMBHSTSTS)) != 0x00) { dev_err(&piix4_adapter->dev, "Failed! (%02x)\n", temp); return -EBUSY; } else { @@ -540,7 +370,7 @@ static int piix4_transaction_io(unsigned } /* start the transaction by setting bit 6 */ - outb_p(inb(SMBusddr + SMBHSTCNT) | 0x040, SMBusddr + SMBHSTCNT); + outb_p(inb(SMBHSTCNT) | 0x040, SMBHSTCNT); /* We will always wait for a fraction of a second! (See PIIX4 docs errata) */ if (srvrworks_csb5_delay) /* Extra delay for SERVERWORKS_CSB5 */ @@ -548,8 +378,8 @@ static int piix4_transaction_io(unsigned else msleep(1); - while ((++timeout < MAX_TIMEOUT) - && ((temp = inb_p(SMBusddr + SMBHSTSTS)) & 0x01)) + while ((++timeout < MAX_TIMEOUT) && + ((temp = inb_p(SMBHSTSTS)) & 0x01)) msleep(1); /* If the SMBus is still busy, we give up */ @@ -575,187 +405,73 @@ static int piix4_transaction_io(unsigned dev_dbg(&piix4_adapter->dev, "Error: no response!\n"); } - if (inb_p(SMBusddr+ SMBHSTSTS) != 0x00) - outb_p(inb(SMBusddr + SMBHSTSTS), SMBusddr + SMBHSTSTS); + if (inb_p(SMBHSTSTS) != 0x00) + outb_p(inb(SMBHSTSTS), SMBHSTSTS); - if ((temp = inb_p(SMBusddr + SMBHSTSTS)) != 0x00) { + if ((temp = inb_p(SMBHSTSTS)) != 0x00) { dev_err(&piix4_adapter->dev, "Failed reset at end of " "transaction (%02x)\n", temp); } dev_dbg(&piix4_adapter->dev, "Transaction (post): CNT=%02x, CMD=%02x, " - "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBusddr + SMBHSTCNT), - inb_p(SMBusddr + SMBHSTCMD), inb_p(SMBusddr + SMBHSTADD), - inb_p(SMBusddr + SMBHSTDAT0), inb_p(SMBusddr + SMBHSTDAT1)); + "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT), + inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0), + inb_p(SMBHSTDAT1)); return result; } - - -/************************************************************************/ -/** Transaction function for primary Controller, IO-mapped - * - * This function access the 1st Controller [SMBus 0] via the i2c_adapter - * if the Controller is IO-mapped - * and call the transaction function to transmit or receive data - * - * \param *adap \IN i2c adapter - * \param addr \IN adress of a Controller Register - * \param flags \IN unused - * \param read_write \IN read or write operation - * \param command \IN ommand to send - * \param size - * \param *data data to send - * - * \return \c 0 On success or error code - */ -static s32 piix4_access_io(struct i2c_adapter * adap, u16 addr, - unsigned short flags, char read_write, u8 command, int size, - union i2c_smbus_data * data) { - int i, len; - int status; - - switch (size) { - case I2C_SMBUS_QUICK: - outb_p((addr << 1) * read_write, piix4_smba0 + SMBHSTADD); - size = PIIX4_QUICK; - break; - case I2C_SMBUS_BYTE: - outb_p((addr << 1) * read_write, piix4_smba0 + SMBHSTADD); - if (read_write == I2C_SMBUS_WRITE) - outb_p(command, piix4_smba0 + SMBHSTCMD); - size = PIIX4_BYTE; - break; - case I2C_SMBUS_BYTE_DATA: - outb_p((addr << 1) | read_write, piix4_smba0 + SMBHSTADD); - outb_p(command, piix4_smba0 + SMBHSTCMD); - if (read_write == I2C_SMBUS_WRITE) - outb_p(data->byte, piix4_smba0 + SMBHSTDAT0); - size = PIIX4_BYTE_DATA; - break; - case I2C_SMBUS_WORD_DATA: - outb_p((addr << 1) | read_write, piix4_smba0 + SMBHSTADD); - outb_p(command, piix4_smba0 + SMBHSTCMD); - if (read_write == I2C_SMBUS_WRITE) { - outb_p(data->word & 0xff, piix4_smba0 + SMBHSTDAT0); - outb_p((data->word & 0xff00) >> 8, piix4_smba0 + SMBHSTDAT1); - } - size = PIIX4_WORD_DATA; - break; - case I2C_SMBUS_BLOCK_DATA: - outb_p((addr << 1) | read_write, piix4_smba0 + SMBHSTADD); - outb_p(command, piix4_smba0 + SMBHSTCMD); - if (read_write == I2C_SMBUS_WRITE) { - len = data->block[0]; - if (len == 0 || len > I2C_SMBUS_BLOCK_MAX) - return -EINVAL; - outb_p(len, piix4_smba0 + SMBHSTDAT0); - i = inb_p(piix4_smba0 + SMBHSTCNT); /* Reset SMBBLKDAT */ - for (i = 1; i <= len; i++) - outb_p(data->block[i], piix4_smba0 + SMBBLKDAT); - } - size = PIIX4_BLOCK_DATA; - break; - default: - dev_warn(&adap->dev, "Unsupported transaction %d\n", size); - return -EOPNOTSUPP; - } - - outb_p((size & 0x1C) + (ENABLE_INT9 & 1), piix4_smba0 + SMBHSTCNT); - - mutex_lock(&funcLock); - - status = piix4_transaction_io(piix4_smba0, adap); - - mutex_unlock(&funcLock); - - if (status) - return status; - - if ((read_write == I2C_SMBUS_WRITE) || (size == PIIX4_QUICK)) - return 0; - - switch (size) { - case PIIX4_BYTE: - case PIIX4_BYTE_DATA: - data->byte = inb_p(piix4_smba0 + SMBHSTDAT0); - break; - case PIIX4_WORD_DATA: - data->word = inb_p(piix4_smba0 + SMBHSTDAT0) - + (inb_p(piix4_smba0 + SMBHSTDAT1) << 8); - break; - case PIIX4_BLOCK_DATA: - data->block[0] = inb_p(piix4_smba0 + SMBHSTDAT0); - if (data->block[0] == 0 || data->block[0] > I2C_SMBUS_BLOCK_MAX) - return -EPROTO; - i = inb_p(piix4_smba0 + SMBHSTCNT); /* Reset SMBBLKDAT */ - for (i = 1; i <= data->block[0]; i++) - data->block[i] = inb_p(piix4_smba0 + SMBBLKDAT); - break; - } - return 0; - -} - -/************************************************************************/ -/** Transaction function for secondary Controller, IO-mapped - * - * This function access the 2nd Controller [SMBus 1] via the i2c_adapter - * if the Controller is IO-mapped, - * and call the transaction function to transmit or receive data - * \param *adap \IN i2c adapter - * \param addr \IN adress of a Controller Register - * \param flags \IN unused - * \param read_write \IN read or write operation - * \param command \IN ommand to send - * \param size - * \param *data data to send - * - * \return \c 0 On success or error code - */ -static s32 sec_piix4_access_io(struct i2c_adapter * adap, u16 addr, - unsigned short flags, char read_write, u8 command, int size, - union i2c_smbus_data * data) { +/* Return negative errno on error. */ +static s32 piix4_access(struct i2c_adapter * adap, u16 addr, + unsigned short flags, char read_write, + 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 status; switch (size) { case I2C_SMBUS_QUICK: - outb_p((addr << 1) | read_write, piix4_smba1 + SMBHSTADD); + outb_p((addr << 1) | read_write, + SMBHSTADD); size = PIIX4_QUICK; break; case I2C_SMBUS_BYTE: - outb_p((addr << 1) | read_write, piix4_smba1 + SMBHSTADD); + outb_p((addr << 1) | read_write, + SMBHSTADD); if (read_write == I2C_SMBUS_WRITE) - outb_p(command, piix4_smba1 + SMBHSTCMD); + outb_p(command, SMBHSTCMD); size = PIIX4_BYTE; break; case I2C_SMBUS_BYTE_DATA: - outb_p((addr << 1) | read_write, piix4_smba1 + SMBHSTADD); - outb_p(command, piix4_smba1 + SMBHSTCMD); + outb_p((addr << 1) | read_write, + SMBHSTADD); + outb_p(command, SMBHSTCMD); if (read_write == I2C_SMBUS_WRITE) - outb_p(data->byte, piix4_smba1 + SMBHSTDAT0); + outb_p(data->byte, SMBHSTDAT0); size = PIIX4_BYTE_DATA; break; case I2C_SMBUS_WORD_DATA: - outb_p((addr << 1) | read_write, piix4_smba1 + SMBHSTADD); - outb_p(command, piix4_smba1 + SMBHSTCMD); + outb_p((addr << 1) | read_write, + SMBHSTADD); + outb_p(command, SMBHSTCMD); if (read_write == I2C_SMBUS_WRITE) { - outb_p(data->word & 0xff, piix4_smba1 + SMBHSTDAT0); - outb_p((data->word & 0xff00) >> 8, piix4_smba1 + SMBHSTDAT1); + outb_p(data->word & 0xff, SMBHSTDAT0); + outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1); } size = PIIX4_WORD_DATA; break; case I2C_SMBUS_BLOCK_DATA: - outb_p((addr << 1) | read_write, piix4_smba1 + SMBHSTADD); - outb_p(command, piix4_smba1 + SMBHSTCMD); + outb_p((addr << 1) | read_write, + SMBHSTADD); + outb_p(command, SMBHSTCMD); if (read_write == I2C_SMBUS_WRITE) { len = data->block[0]; if (len == 0 || len > I2C_SMBUS_BLOCK_MAX) return -EINVAL; - outb_p(len, piix4_smba1 + SMBHSTDAT0); - i = inb_p(piix4_smba1 + SMBHSTCNT); /* Reset SMBBLKDAT */ + outb_p(len, SMBHSTDAT0); + i = inb_p(SMBHSTCNT); /* Reset SMBBLKDAT */ for (i = 1; i <= len; i++) - outb_p(data->block[i], piix4_smba1 + SMBBLKDAT); + outb_p(data->block[i], SMBBLKDAT); } size = PIIX4_BLOCK_DATA; break; @@ -764,281 +480,49 @@ static s32 sec_piix4_access_io(struct i2 return -EOPNOTSUPP; } - outb_p((size & 0x1C) + (ENABLE_INT9 & 1), piix4_smba1 + SMBHSTCNT); - - mutex_lock(&funcLock); - - status = piix4_transaction_io(piix4_smba1,adap); - - mutex_unlock(&funcLock); + outb_p((size & 0x1C) + (ENABLE_INT9 & 1), SMBHSTCNT); + status = piix4_transaction(adap); if (status) return status; if ((read_write == I2C_SMBUS_WRITE) || (size == PIIX4_QUICK)) return 0; - switch (size) { - case PIIX4_BYTE: - case PIIX4_BYTE_DATA: - data->byte = inb_p(piix4_smba1 + SMBHSTDAT0); - break; - case PIIX4_WORD_DATA: - data->word = inb_p(piix4_smba1 + SMBHSTDAT0) - + (inb_p(piix4_smba1 + SMBHSTDAT1) << 8); - break; - case PIIX4_BLOCK_DATA: - data->block[0] = inb_p(piix4_smba1 + SMBHSTDAT0); - if (data->block[0] == 0 || data->block[0] > I2C_SMBUS_BLOCK_MAX) - return -EPROTO; - i = inb_p(piix4_smba1 + SMBHSTCNT); /* Reset SMBBLKDAT */ - for (i = 1; i <= data->block[0]; i++) - data->block[i] = inb_p(piix4_smba1 + SMBBLKDAT); - break; - } - return 0; - -} - - -/************************************************************************/ -/** separate transaction function for secondary Controller, mem-mapped - * - * \return \c 0 On success or error code - */ - -static int piix4_transaction_mem(void) { - int temp; - int result = 0; - int timeout = 0; - - dev_dbg(&piix4_adapter1.dev, "Transaction (pre): CNT=%02x, CMD=%02x, " - "ADD=%02x, DAT0=%02x, DAT1=%02x\n", readb(virt_addr + SMBHSTCNT), - readb(virt_addr + SMBHSTCMD), readb(virt_addr + SMBHSTADD), - readb(virt_addr + SMBHSTDAT0), readb(virt_addr + SMBHSTDAT1)); - - /* Make sure the SMBus host is ready to start transmitting */ - if ((temp = readb(virt_addr + SMBHSTSTS)) != 0x00) { - dev_dbg(&piix4_adapter1.dev, "SMBus busy (%02x). " - "Resetting...\n", temp); - writeb(temp, virt_addr + SMBHSTSTS); - if ((temp = readb(virt_addr + SMBHSTSTS)) != 0x00) { - dev_err(&piix4_adapter1.dev, "Failed! (%02x)\n", temp); - return -EBUSY; - } else { - dev_dbg(&piix4_adapter1.dev, "Successful!\n"); - } - } - - /* start the transaction by setting bit 6 */ - writeb(readb(virt_addr + SMBHSTCNT) | 0x040, virt_addr + SMBHSTCNT); - - /* We will always wait for a fraction of a second! (See PIIX4 docs errata) */ - if (srvrworks_csb5_delay) /* Extra delay for SERVERWORKS_CSB5 */ - msleep(2); - else - msleep(1); - - while ((++timeout < MAX_TIMEOUT) - && ((temp = readb(virt_addr + SMBHSTSTS)) & 0x01)) - msleep(1); - - /* If the SMBus is still busy, we give up */ - if (timeout == MAX_TIMEOUT) { - dev_err(&piix4_adapter1.dev, "SMBus Timeout!\n"); - result = -ETIMEDOUT; - } - - if (temp & 0x10) { - result = -EIO; - dev_err(&piix4_adapter1.dev, "Error: Failed bus transaction\n"); - } - - if (temp & 0x08) { - result = -EIO; - dev_dbg(&piix4_adapter1.dev, "Bus collision! SMBus may be " - "locked until next hard reset. (sorry!)\n"); - /* Clock stops and slave is stuck in mid-transmission */ - } - - if (temp & 0x04) { - result = -ENXIO; - dev_dbg(&piix4_adapter1.dev, "Error: no response!\n"); - } - - if (readb(virt_addr + SMBHSTSTS) != 0x00) - writeb(readb(virt_addr + SMBHSTSTS), virt_addr + SMBHSTSTS); - - if ((temp = readb(virt_addr + SMBHSTSTS)) != 0x00) { - dev_err(&piix4_adapter1.dev, "Failed reset at end of " - "transaction (%02x)\n", temp); - } - dev_dbg(&piix4_adapter1.dev, "Transaction (post): CNT=%02x, CMD=%02x, " - "ADD=%02x, DAT0=%02x, DAT1=%02x\n", readb(virt_addr + SMBHSTCNT), - readb(virt_addr + SMBHSTCMD), readb(virt_addr + SMBHSTADD), - readb(virt_addr + SMBHSTDAT0), readb(virt_addr + SMBHSTDAT1)); - - return result; -} - - -/************************************************************************/ -/** Transaction function for both Controllers, mem-mapped - * - * This function accesses the given Controller via the i2c_adapter - * if the Controller is IO-mapped - * and call the transaction function to transmit or receive data - * - * \param *adap \IN i2c adapter - * \param addr \IN adress of a Controller Register - * \param flags \IN unused - * \param read_write \IN read or write operation - * \param command \IN ommand to send - * \param size - * \param *data data to send - * - * \return \c 0 On success or error code - */ - -static s32 piix4_access_mem(struct i2c_adapter * adap, u16 addr, - unsigned short flags, char read_write, u8 command, int size, - union i2c_smbus_data * data) { - int i, len; - int status; - - switch (size) { - case I2C_SMBUS_QUICK: - writeb((addr << 1) | read_write, virt_addr + SMBHSTADD); - size = PIIX4_QUICK; - break; - case I2C_SMBUS_BYTE: - writeb((addr << 1) | read_write, virt_addr + SMBHSTADD); - if (read_write == I2C_SMBUS_WRITE) - writeb(command, virt_addr + SMBHSTCMD); - size = PIIX4_BYTE; - break; - case I2C_SMBUS_BYTE_DATA: - writeb((addr << 1) | read_write, virt_addr + SMBHSTADD); - writeb(command, virt_addr + SMBHSTCMD); - if (read_write == I2C_SMBUS_WRITE) - writeb(data->byte, virt_addr + SMBHSTDAT0); - size = PIIX4_BYTE_DATA; - break; - case I2C_SMBUS_WORD_DATA: - writeb((addr << 1) | read_write, virt_addr + SMBHSTADD); - writeb(command, virt_addr + SMBHSTCMD); - if (read_write == I2C_SMBUS_WRITE) { - writeb(data->word & 0xff, virt_addr + SMBHSTDAT0); - writeb((data->word & 0xff00) >> 8, virt_addr + SMBHSTDAT1); - } - size = PIIX4_WORD_DATA; - break; - case I2C_SMBUS_BLOCK_DATA: - writeb((addr << 1) | read_write, virt_addr + SMBHSTADD); - writeb(command, virt_addr + SMBHSTCMD); - if (read_write == I2C_SMBUS_WRITE) { - len = data->block[0]; - if (len == 0 || len > I2C_SMBUS_BLOCK_MAX) - return -EINVAL; - writeb(len, virt_addr + SMBHSTDAT0); - i = readb(virt_addr + SMBHSTCNT); /* Reset SMBBLKDAT */ - for (i = 1; i <= len; i++) - writeb(data->block[i], virt_addr + SMBBLKDAT); - } - size = PIIX4_BLOCK_DATA; - break; - default: - dev_warn(&adap->dev, "Unsupported transaction %d\n", size); - return -EOPNOTSUPP; - } - - writeb((size & 0x1C) + (ENABLE_INT9 & 1), virt_addr + SMBHSTCNT); - - status = piix4_transaction_mem(); - if (status) - return status; - - if ((read_write == I2C_SMBUS_WRITE) || (size == PIIX4_QUICK)) - return 0; switch (size) { case PIIX4_BYTE: case PIIX4_BYTE_DATA: - data->byte = readb(virt_addr + SMBHSTDAT0); + data->byte = inb_p(SMBHSTDAT0); break; case PIIX4_WORD_DATA: - data->word = readb(virt_addr + SMBHSTDAT0) - + (readb(virt_addr + SMBHSTDAT1) << 8); + data->word = inb_p(SMBHSTDAT0) + (inb_p(SMBHSTDAT1) << 8); break; case PIIX4_BLOCK_DATA: - data->block[0] = readb(virt_addr + SMBHSTDAT0); + data->block[0] = inb_p(SMBHSTDAT0); if (data->block[0] == 0 || data->block[0] > I2C_SMBUS_BLOCK_MAX) return -EPROTO; - i = readb(virt_addr + SMBHSTCNT); /* Reset SMBBLKDAT */ + i = inb_p(SMBHSTCNT); /* Reset SMBBLKDAT */ for (i = 1; i <= data->block[0]; i++) - data->block[i] = readb(virt_addr + SMBBLKDAT); + data->block[i] = inb_p(SMBBLKDAT); break; } return 0; } - -/************************************************************************/ -/** return capabilities of this Hardware - * - * \return capabilities flags - */ -static u32 piix4_func(struct i2c_adapter *adapter) { - return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA - | I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BLOCK_DATA; +static u32 piix4_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | + I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | + I2C_FUNC_SMBUS_BLOCK_DATA; } -/*---------------- 1st Controller [SMBus0]----------------*/ - -/* algorithm IO-mapped [SMBus0] */ -static const struct i2c_algorithm smbus_algorithm0 = { - .smbus_xfer = piix4_access_io, - .functionality = piix4_func, -}; - -/* i2c_adapter IO-mapped [SMBus0] */ -static struct i2c_adapter piix4_adapter0 = { - .owner = THIS_MODULE, - .class = I2C_CLASS_HWMON | I2C_CLASS_SPD, - .algo = &smbus_algorithm0, -}; - -/*---------------- 2nd Controller [SMBus1]----------------*/ - -/* algorithm MEM-mapped [SMBus1] */ -static const struct i2c_algorithm smbus_algorithm1 = { - .smbus_xfer = piix4_access_mem, +static const struct i2c_algorithm smbus_algorithm = { + .smbus_xfer = piix4_access, .functionality = piix4_func, }; -/* algorithm IO-mapped [SMBus1] */ -static const struct i2c_algorithm smbus_algorithm2 = { - .smbus_xfer = sec_piix4_access_io, - .functionality = piix4_func, -}; - -/* i2c_adapter MEM-mapped [SMBus1] */ -static struct i2c_adapter piix4_adapter1 = { - .owner = THIS_MODULE, - .class = I2C_CLASS_HWMON | I2C_CLASS_SPD, - .algo = &smbus_algorithm1, -}; - -/* i2c_adapter IO-mapped [SMBus1] */ -static struct i2c_adapter piix4_adapter2 = { - .owner = THIS_MODULE, - .class = I2C_CLASS_HWMON | I2C_CLASS_SPD, - .algo = &smbus_algorithm2, -}; - - -static const struct pci_device_id 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_82443MX_3) }, { PCI_DEVICE(PCI_VENDOR_ID_EFAR, PCI_DEVICE_ID_EFAR_SLC90E66_3) }, @@ -1047,150 +531,143 @@ static const struct pci_device_id piix4_ { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP400_SMBUS) }, { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_SBX00_SMBUS) }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_HUDSON2_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x790b) }, + { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, + PCI_DEVICE_ID_SERVERWORKS_OSB4) }, + { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, + PCI_DEVICE_ID_SERVERWORKS_CSB5) }, { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, - PCI_DEVICE_ID_SERVERWORKS_OSB4) }, { PCI_DEVICE( - PCI_VENDOR_ID_SERVERWORKS, - PCI_DEVICE_ID_SERVERWORKS_CSB5) }, { PCI_DEVICE( - PCI_VENDOR_ID_SERVERWORKS, - PCI_DEVICE_ID_SERVERWORKS_CSB6) }, { PCI_DEVICE( - PCI_VENDOR_ID_SERVERWORKS, - PCI_DEVICE_ID_SERVERWORKS_HT1000SB) }, { PCI_DEVICE( - PCI_VENDOR_ID_SERVERWORKS, - PCI_DEVICE_ID_SERVERWORKS_HT1100LD) }, { 0, } }; + PCI_DEVICE_ID_SERVERWORKS_CSB6) }, + { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, + PCI_DEVICE_ID_SERVERWORKS_HT1000SB) }, + { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, + PCI_DEVICE_ID_SERVERWORKS_HT1100LD) }, + { 0, } +}; + MODULE_DEVICE_TABLE (pci, piix4_ids); -/************************************************************************/ -/** Probing function for SMB Controller - * - * \param *dev \IN PCI device struct - * \param *id \IN PCI device ID - * - * \return \c 0 On success or error code - */ +static struct i2c_adapter *piix4_main_adapter; +static struct i2c_adapter *piix4_aux_adapter; -static int piix4_probe(struct pci_dev *dev, - const struct pci_device_id *id) +static int piix4_add_adapter(struct pci_dev *dev, unsigned short smba, + struct i2c_adapter **padap) { - /* 1 = Controller not in use */ - int ctr1_retval = 1; - int ctr2_retval = 1; - - mutex_init(&funcLock); - mutex_unlock(&funcLock); + struct i2c_adapter *adap; + struct i2c_piix4_adapdata *adapdata; + int retval; - if ((dev->vendor == PCI_VENDOR_ID_ATI && - dev->device == PCI_DEVICE_ID_ATI_SBX00_SMBUS && - dev->revision >= 0x40) || - dev->vendor == PCI_VENDOR_ID_AMD) { - /* base address location etc changed in SB800 */ - ctr1_retval = piix4_setup_sb800(dev, id); - ctr2_retval = sec_piix4_setup_sb800(dev,id); + adap = kzalloc(sizeof(*adap), GFP_KERNEL); + if (adap == NULL) { + release_region(smba, SMBIOSIZE); + return -ENOMEM; } - else - ctr1_retval = piix4_setup(dev, id); - - /* Is just the controller 1 in use, an has a fault? */ - if (ctr1_retval != 0 && ctr2_retval == 1) - return ctr1_retval; - - if( ctr1_retval == 0 ) { - /* set up the sysfs linkage to our parent device */ - piix4_adapter0.dev.parent = &dev->dev; - - snprintf(piix4_adapter0.name, sizeof(piix4_adapter0.name), - "SMBus PIIX4 adapter at 0x%04x", piix4_smba0); + adap->owner = THIS_MODULE; + adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD; + adap->algo = &smbus_algorithm; - /* Add 1st I2C adapter */ - if ((ctr1_retval = i2c_add_adapter(&piix4_adapter0))) { - dev_err(&dev->dev, "Couldn't register adapter 0!\n"); - release_region(piix4_smba0, SMBIOSIZE); - piix4_smba0 = 0; + adapdata = kzalloc(sizeof(*adapdata), GFP_KERNEL); + if (adapdata == NULL) { + kfree(adap); + release_region(smba, SMBIOSIZE); + return -ENOMEM; } - /* if the 2nd controller is not in use, probe is ready */ - if(ctr2_retval == 1) - return ctr1_retval; - } + adapdata->smba = smba; - if( ctr2_retval == 0 ) { - /* add adapter 1 if the [SMBus1] is MEM-mapped */ - if(SMBusMap == MEMMAP) { - piix4_adapter1.dev.parent = &dev->dev; + /* set up the sysfs linkage to our parent device */ + adap->dev.parent = &dev->dev; - snprintf(piix4_adapter1.name, sizeof(piix4_adapter1.name), - "SMBus PIIX4 2nd adapter at 0x%08x", piix4_smba1); + snprintf(adap->name, sizeof(adap->name), + "SMBus PIIX4 adapter at %04x", smba); - ctr2_retval = i2c_add_adapter(&piix4_adapter1); + 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; } - /* add adapter 2 if the [SMBus1] is IO-mapped */ - else { - piix4_adapter2.dev.parent = &dev->dev; - snprintf(piix4_adapter2.name, sizeof(piix4_adapter2.name), - "SMBus PIIX4 2nd adapter at 0x%08x", piix4_smba1); + *padap = adap; + return 0; +} - ctr2_retval = i2c_add_adapter(&piix4_adapter2); +static int piix4_probe(struct pci_dev *dev, const struct pci_device_id *id) +{ + int retval; - } + if ((dev->vendor == PCI_VENDOR_ID_ATI && + dev->device == PCI_DEVICE_ID_ATI_SBX00_SMBUS && + dev->revision >= 0x40) || + dev->vendor == PCI_VENDOR_ID_AMD) + /* base address location etc changed in SB800 */ + retval = piix4_setup_sb800(dev, id, 0); + else + retval = piix4_setup(dev, id); - /* Could the adapter of the [SMBus1] be added? */ - if( ctr2_retval ) { - dev_err(&dev->dev, "Couldn't register SMBus adapter 1!\n"); - printk("Couldn´t register SMBus adapter 1\n"); - relAdressSpace(piix4_smba1, SMBMSIZE,SMBusMap); - piix4_smba1 = 0; + /* If no main SMBus found, give up */ + if (retval < 0) + return retval; + + /* Try to register main SMBus adapter, give up if we can't */ + retval = piix4_add_adapter(dev, retval, &piix4_main_adapter); + if (retval < 0) + return retval; + + /* Check for auxiliary SMBus on some AMD chipsets */ + retval = -ENODEV; + + if (dev->vendor == PCI_VENDOR_ID_ATI && + dev->device == PCI_DEVICE_ID_ATI_SBX00_SMBUS) { + if (dev->revision < 0x40) { + retval = piix4_setup_aux(dev, id, 0x58); + } else { + /* SB800 added aux bus too */ + retval = piix4_setup_sb800(dev, id, 1); } } + if (dev->vendor == PCI_VENDOR_ID_AMD && + dev->device == PCI_DEVICE_ID_AMD_HUDSON2_SMBUS) { + retval = piix4_setup_sb800(dev, id, 1); + } - /* if both I2C Controller couldn´t initialize => there is no Controller */ - if( ctr1_retval && ctr2_retval ) - return -ENODEV; - - /* if Controller 1 couldn´t initialize */ - if( ctr1_retval ) - printk("SMBus0 could not be initialize\n"); - - /* if Controller 2 couldn´t initialize */ - if( ctr2_retval ) - printk("SBus1 could not be intitialize\n"); + 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 0; } - -/************************************************************************/ -/** Removing function for SMB Controller - * - * \param *dev \IN PCI device struct - * - * \return - - */ -static void piix4_remove(struct pci_dev *dev) +static void piix4_adap_remove(struct i2c_adapter *adap) { - if (piix4_smba0) { - i2c_del_adapter(&piix4_adapter0); - release_region(piix4_smba0, SMBIOSIZE); - piix4_smba0 = 0; - } + struct i2c_piix4_adapdata *adapdata = i2c_get_adapdata(adap); - /* release mem region of 2nd Controller [SMBus1] */ - if (piix4_smba1) { - if(SMBusMap == MEMMAP) { - i2c_del_adapter(&piix4_adapter1); - release_mem_region(piix4_smba1, SMBMSIZE); - - /* unmap the virtual adress */ - iounmap(virt_addr); + if (adapdata->smba) { + i2c_del_adapter(adap); + release_region(adapdata->smba, SMBIOSIZE); + kfree(adapdata); + kfree(adap); } - else if(SMBusMap == IOMAP) { - i2c_del_adapter(&piix4_adapter2); - release_region(piix4_smba1, SMBMSIZE); +} + +static void piix4_remove(struct pci_dev *dev) +{ + if (piix4_main_adapter) { + piix4_adap_remove(piix4_main_adapter); + piix4_main_adapter = NULL; } - piix4_smba1 = 0; + if (piix4_aux_adapter) { + piix4_adap_remove(piix4_aux_adapter); + piix4_aux_adapter = NULL; } } @@ -1198,23 +675,12 @@ static struct pci_driver piix4_driver = .name = "piix4_smbus", .id_table = piix4_ids, .probe = piix4_probe, -// .remove = __devexit_p(piix4_remove), + .remove = piix4_remove, }; -static int __init i2c_piix4_init(void) -{ - return pci_register_driver(&piix4_driver); -} - -static void __exit i2c_piix4_exit(void) -{ - pci_unregister_driver(&piix4_driver); -} +module_pci_driver(piix4_driver); MODULE_AUTHOR("Frodo Looijaard <frodol@xxxxxx> and " "Philip Edelbrock <phil@xxxxxxxxxxxxx>"); MODULE_DESCRIPTION("PIIX4 SMBus driver"); MODULE_LICENSE("GPL"); - -module_init(i2c_piix4_init); -module_exit(i2c_piix4_exit); -- Dr. Christian Herzog <herzog@xxxxxxxxxxxx> support: +41 44 633 26 68 IT Services Group, HPT H 8 voice: +41 44 633 39 50 Department of Physics, ETH Zurich 8093 Zurich, Switzerland http://nic.phys.ethz.ch/ -- To unsubscribe from this list: send the line "unsubscribe linux-i2c" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html