I2C support for AMD Hudson-1
Dear list,
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.
I expect those boards to become at least as popular as their alix predecessors were, so out-of-the-box kernel support would be nice.
thanks and kind regards,
-Christian
Signature · 9 lines
Dr. Christian Herzog <[email protected]> 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/ _______________________________________________ lm-sensors mailing list [email protected] http://lists.lm-sensors.org/mailman/listinfo/lm-sensors
A message that is not in the archive (sent off-list or not yet received): [email protected]
Quoted 14 lines · Christian Herzog
Dear list,
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.
I expect those boards to become at least as popular as their alix predecessors were, so out-of-the-box kernel support would be nice.
Wrong mailing list. Copying linux-i2c.
Guenter
A message that is not in the archive (sent off-list or not yet received): [email protected]
Quoted 10 lines
Quoted 10 lines
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
Quoted 14 lines · Wolfram Sang
Quoted 10 lines
Quoted 10 lines
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 :(
Quoted 6 lines
What you/someone can do:
* get the patch
* port it to a recent kernel and verify it still works
* readDocumentation/SubmittingPatches
* send the patch
... with me in Cc, I'll review it.
Signature · 1 line
Jean Delvare
A message that is not in the archive (sent off-list or not yet received): [email protected]
A message that is not in the archive (sent off-list or not yet received): [email protected]
A message that is not in the archive (sent off-list or not yet received): [email protected]
A message that is not in the archive (sent off-list or not yet received): [email protected]
Hi Christian,
Quoted 4 lines · Christian Herzog
sorry to bother you again, but this might save you some work: I just compiled 3.13.0-rc7 on the apu board and i2c works out of the box. I'm pretty stumped as I'm pretty sure it didn't work OOTB on -rc3, but now it does.. Are you aware of any Hudson-1 specific changes recently?
I am not aware of anything related to Hudson-1. I don't even know the PCI IDs for that device.
The git history tells that there was no change to the i2c-piix4 driver since kernel version 3.12-rc1. This is when support for secondary SMBus on AMD SB800 and AMD FCH chipsets was added. I think FCH and Hudson-2 are the same thing, not sure how Hudson-1 fits into the picture.
Are you certain that the kernel version change fixed it? A BIOS update could have helped as well, or even just changing some BIOS settings.
Another possibility is that some PCI or architecture quirk was added meanwhile. However a quick search did not reveal anything between 3.13-rc3 and 3.13-rc7.
If you are really sure that 3.13-rc3 didn't work and 3.13-rc7 does work, and you really want to understand why, then you can bisect the git kernel tree between both points and it'll point you to the commit that fixed it.
As for me, if things work for you now, I see no point in investigating further. As Wolfram already pointed out, your contribution came in a format we can't do anything with. The patch is huge, reversed, based on a source file which had indentation changes, mixes actual changes with (mostly unjustified) white-space changes, etc. If you ever need to get changes into the kernel, please follow the rules listed in Documentation/SubmittingPatches, otherwise nobody will review your work, no matter how needed you think it is.
Signature · 1 line
Jean Delvare
A message that is not in the archive (sent off-list or not yet received): [email protected]
Dear Jean,
thanks for your reply.
Quoted 4 lines
The git history tells that there was no change to the i2c-piix4 driver since kernel version 3.12-rc1. This is when support for secondary SMBus on AMD SB800 and AMD FCH chipsets was added. I think FCH and Hudson-2 are the same thing, not sure how Hudson-1 fits into the picture.
as far as I understand it, both Hudsons are FCHs in AMD speak. It is very reasonable to assume that indeed 3.12-rc1 did add Hudson-1 support if that's when secondary SMBus support was introduced. I think it was mainly this 2nd channel that was missing in the 'old' driver.
Quoted 2 lines
Are you certain that the kernel version change fixed it? A BIOS update could have helped as well, or even just changing some BIOS settings.
nope, since the apu board has a very minimal BIOS and I didn't do anything in this regard.
Quoted 4 lines
If you are really sure that 3.13-rc3 didn't work and 3.13-rc7 does work, and you really want to understand why, then you can bisect the git kernel tree between both points and it'll point you to the commit that fixed it.
I thought so, but with the above it is very likely that it started working as of 3.12-rc1 and I somehow missed it in 3.13-rc3. Unfortunately I can't check now since the board is being used elsewhere.
Quoted 2 lines
As for me, if things work for you now, I see no point in investigating further. As Wolfram already pointed out, your contribution came in a
I second this pragmatic approach. Goal was to add support and support we have.
Quoted 6 lines
format we can't do anything with. The patch is huge, reversed, based on a source file which had indentation changes, mixes actual changes with (mostly unjustified) white-space changes, etc. If you ever need to get changes into the kernel, please follow the rules listed in
Documentation/SubmittingPatches, otherwise nobody will review your work, no matter how needed you think it is.
I apologize. As stated before, I'm not the author of the patch and simply felt not comfortable enough in the code to clean it up more than just make it compile on a new kernel. Next time I'll try harder.
thanks for you work, we have support and are happy. I'll inform the author of the patch.
cheers,
-Christian
Signature · 4 lines
Dr. Christian Herzog <[email protected]> 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/
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
Quoted 16 lines · Wolfram Sang
Quoted 10 lines
Quoted 10 lines
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:
Quoted 9 lines
* get the patch
* port it to a recent kernel and verify it still works
* readDocumentation/SubmittingPatches
* send the patchRegards,
Wolfram
#------------------------------------- PATCH ------------#
i2c-piix4.c.orig renamed from i2c-piix4.c +261 -795
@@ -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 <[email protected]> and Philip Edelbrock <[email protected]>
@@ -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 <[email protected]> and " "Philip Edelbrock <[email protected]>"); MODULE_DESCRIPTION("PIIX4 SMBus driver"); MODULE_LICENSE("GPL"); - -module_init(i2c_piix4_init); -module_exit(i2c_piix4_exit);
Signature · 4 lines
Dr. Christian Herzog <[email protected]> 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/
A message that is not in the archive (sent off-list or not yet received): [email protected]
Quoted 10 lines · Christian Herzog
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.cof 3.13-rc4. I also prepared a .tgz that contains
- the original archive from men.de
- my modified driver
- the patch itself
Thanks for posting a patch known to work with a recent kernel. Yet, this is way too intrusive. We need minimal changes in logical steps to get a new feature supported. Ping to Jean for the details, x86 drivers are his expertise.
Dear all,
thanks for the feedback. I was already in contact with Jean because I noticed the following:
I recently compiled 3.13.0-rc7 on my PC Engines apu beta box, and I2C works out of the box, without the need for my patch. I'm still looking for somebody who could shed some light on this situation - chances are we don't need the patch any longer.
So: is anybody aware of any Hudson-1 related changes to the i2c-piix4 code?
thanks,
-Christian
Quoted 17 lines · Wolfram Sang
Quoted 10 lines · Christian Herzog
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.cof 3.13-rc4. I also prepared a .tgz that contains
- the original archive from men.de
- my modified driver
- the patch itselfThanks for posting a patch known to work with a recent kernel. Yet, this is way too intrusive. We need minimal changes in logical steps to get a new feature supported. Ping to Jean for the details, x86 drivers are his expertise.
Signature · 4 lines
Dr. Christian Herzog <[email protected]> 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/
Quoted 12 lines · Wolfram Sang
Quoted 10 lines · Christian Herzog
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.cof 3.13-rc4. I also prepared a .tgz that contains
- the original archive from men.de
- my modified driver
- the patch itself
Quoted 4 lines
Thanks for posting a patch known to work with a recent kernel. Yet, this is way too intrusive. We need minimal changes in logical steps to get a new feature supported. Ping to Jean for the details, x86 drivers are his expertise.
On my to-do list, but swamped by more urgent matters at the moment :(
Signature · 1 line
Jean Delvare