summaryrefslogtreecommitdiffstats
path: root/drivers/i2c/busses
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/i2c/busses')
-rw-r--r--drivers/i2c/busses/Kconfig18
-rw-r--r--drivers/i2c/busses/Makefile3
-rw-r--r--drivers/i2c/busses/i2c-ali1535.c2
-rw-r--r--drivers/i2c/busses/i2c-ali15x3.c2
-rw-r--r--drivers/i2c/busses/i2c-amd756.c2
-rw-r--r--drivers/i2c/busses/i2c-amd8111.c4
-rw-r--r--drivers/i2c/busses/i2c-i801.c7
-rw-r--r--drivers/i2c/busses/i2c-imx.c86
-rw-r--r--drivers/i2c/busses/i2c-iop3xx.c6
-rw-r--r--drivers/i2c/busses/i2c-isch.c2
-rw-r--r--drivers/i2c/busses/i2c-mpc.c10
-rw-r--r--drivers/i2c/busses/i2c-mv64xxx.c3
-rw-r--r--drivers/i2c/busses/i2c-piix4.c12
-rw-r--r--drivers/i2c/busses/i2c-pnx.c9
-rw-r--r--drivers/i2c/busses/i2c-powermac.c139
-rw-r--r--drivers/i2c/busses/i2c-sis5595.c2
-rw-r--r--drivers/i2c/busses/i2c-sis630.c2
-rw-r--r--drivers/i2c/busses/i2c-sis96x.c2
-rw-r--r--drivers/i2c/busses/i2c-stub.c34
-rw-r--r--drivers/i2c/busses/i2c-viapro.c2
-rw-r--r--drivers/i2c/busses/i2c-voodoo3.c248
21 files changed, 195 insertions, 400 deletions
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 737335ff2b2..5f318ce2977 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -128,7 +128,7 @@ config I2C_PIIX4
ATI SB600
ATI SB700
ATI SB800
- AMD SB900
+ AMD Hudson-2
Serverworks OSB4
Serverworks CSB5
Serverworks CSB6
@@ -640,22 +640,6 @@ config I2C_TINY_USB
This driver can also be built as a module. If so, the module
will be called i2c-tiny-usb.
-comment "Graphics adapter I2C/DDC channel drivers"
- depends on PCI
-
-config I2C_VOODOO3
- tristate "Voodoo 3 (DEPRECATED)"
- depends on PCI
- select I2C_ALGOBIT
- help
- If you say yes to this option, support will be included for the
- Voodoo 3 I2C interface. This driver is deprecated and you should
- use the tdfxfb driver instead, which additionally provides
- framebuffer support.
-
- This driver can also be built as a module. If so, the module
- will be called i2c-voodoo3.
-
comment "Other I2C/SMBus bus drivers"
config I2C_ACORN
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index ff937ac69f5..302c551977b 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -61,9 +61,6 @@ obj-$(CONFIG_I2C_PARPORT_LIGHT) += i2c-parport-light.o
obj-$(CONFIG_I2C_TAOS_EVM) += i2c-taos-evm.o
obj-$(CONFIG_I2C_TINY_USB) += i2c-tiny-usb.o
-# Graphics adapter I2C/DDC channel drivers
-obj-$(CONFIG_I2C_VOODOO3) += i2c-voodoo3.o
-
# Other I2C/SMBus bus drivers
obj-$(CONFIG_I2C_ACORN) += i2c-acorn.o
obj-$(CONFIG_I2C_ELEKTOR) += i2c-elektor.o
diff --git a/drivers/i2c/busses/i2c-ali1535.c b/drivers/i2c/busses/i2c-ali1535.c
index d108450df06..8de7d7b87bb 100644
--- a/drivers/i2c/busses/i2c-ali1535.c
+++ b/drivers/i2c/busses/i2c-ali1535.c
@@ -138,7 +138,7 @@ static unsigned short ali1535_smba;
Note the differences between kernels with the old PCI BIOS interface and
newer kernels with the real PCI interface. In compat.h some things are
defined to make the transition easier. */
-static int ali1535_setup(struct pci_dev *dev)
+static int __devinit ali1535_setup(struct pci_dev *dev)
{
int retval = -ENODEV;
unsigned char temp;
diff --git a/drivers/i2c/busses/i2c-ali15x3.c b/drivers/i2c/busses/i2c-ali15x3.c
index d627fceb790..e7e3205f128 100644
--- a/drivers/i2c/busses/i2c-ali15x3.c
+++ b/drivers/i2c/busses/i2c-ali15x3.c
@@ -131,7 +131,7 @@ MODULE_PARM_DESC(force_addr,
static struct pci_driver ali15x3_driver;
static unsigned short ali15x3_smba;
-static int ali15x3_setup(struct pci_dev *ALI15X3_dev)
+static int __devinit ali15x3_setup(struct pci_dev *ALI15X3_dev)
{
u16 a;
unsigned char temp;
diff --git a/drivers/i2c/busses/i2c-amd756.c b/drivers/i2c/busses/i2c-amd756.c
index f7d6fe9c49b..8f0b90ef8c7 100644
--- a/drivers/i2c/busses/i2c-amd756.c
+++ b/drivers/i2c/busses/i2c-amd756.c
@@ -364,7 +364,7 @@ static int __devinit amd756_probe(struct pci_dev *pdev,
error = acpi_check_region(amd756_ioport, SMB_IOSIZE,
amd756_driver.name);
if (error)
- return error;
+ return -ENODEV;
if (!request_region(amd756_ioport, SMB_IOSIZE, amd756_driver.name)) {
dev_err(&pdev->dev, "SMB region 0x%x already in use!\n",
diff --git a/drivers/i2c/busses/i2c-amd8111.c b/drivers/i2c/busses/i2c-amd8111.c
index a7c59908c45..5b4ad86ca16 100644
--- a/drivers/i2c/busses/i2c-amd8111.c
+++ b/drivers/i2c/busses/i2c-amd8111.c
@@ -376,8 +376,10 @@ static int __devinit amd8111_probe(struct pci_dev *dev,
smbus->size = pci_resource_len(dev, 0);
error = acpi_check_resource_conflict(&dev->resource[0]);
- if (error)
+ if (error) {
+ error = -ENODEV;
goto out_kfree;
+ }
if (!request_region(smbus->base, smbus->size, amd8111_driver.name)) {
error = -EBUSY;
diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
index 9d2c5adf5d4..df6ab553f97 100644
--- a/drivers/i2c/busses/i2c-i801.c
+++ b/drivers/i2c/busses/i2c-i801.c
@@ -732,8 +732,10 @@ static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id
}
err = acpi_check_resource_conflict(&dev->resource[SMBBAR]);
- if (err)
+ if (err) {
+ err = -ENODEV;
goto exit;
+ }
err = pci_request_region(dev, SMBBAR, i801_driver.name);
if (err) {
@@ -765,6 +767,9 @@ static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id
/* set up the sysfs linkage to our parent device */
i801_adapter.dev.parent = &dev->dev;
+ /* Retry up to 3 times on lost arbitration */
+ i801_adapter.retries = 3;
+
snprintf(i801_adapter.name, sizeof(i801_adapter.name),
"SMBus I801 adapter at %04lx", i801_smba);
err = i2c_add_adapter(&i801_adapter);
diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c
index 4afba3ec2a6..e3654d683e1 100644
--- a/drivers/i2c/busses/i2c-imx.c
+++ b/drivers/i2c/busses/i2c-imx.c
@@ -120,19 +120,26 @@ struct imx_i2c_struct {
wait_queue_head_t queue;
unsigned long i2csr;
unsigned int disable_delay;
+ int stopped;
+ unsigned int ifdr; /* IMX_I2C_IFDR */
};
/** Functions for IMX I2C adapter driver ***************************************
*******************************************************************************/
-static int i2c_imx_bus_busy(struct imx_i2c_struct *i2c_imx)
+static int i2c_imx_bus_busy(struct imx_i2c_struct *i2c_imx, int for_busy)
{
unsigned long orig_jiffies = jiffies;
+ unsigned int temp;
dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__);
- /* wait for bus not busy */
- while (readb(i2c_imx->base + IMX_I2C_I2SR) & I2SR_IBB) {
+ while (1) {
+ temp = readb(i2c_imx->base + IMX_I2C_I2SR);
+ if (for_busy && (temp & I2SR_IBB))
+ break;
+ if (!for_busy && !(temp & I2SR_IBB))
+ break;
if (signal_pending(current)) {
dev_dbg(&i2c_imx->adapter.dev,
"<%s> I2C Interrupted\n", __func__);
@@ -179,41 +186,62 @@ static int i2c_imx_acked(struct imx_i2c_struct *i2c_imx)
return 0;
}
-static void i2c_imx_start(struct imx_i2c_struct *i2c_imx)
+static int i2c_imx_start(struct imx_i2c_struct *i2c_imx)
{
unsigned int temp = 0;
+ int result;
dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__);
+ clk_enable(i2c_imx->clk);
+ writeb(i2c_imx->ifdr, i2c_imx->base + IMX_I2C_IFDR);
/* Enable I2C controller */
+ writeb(0, i2c_imx->base + IMX_I2C_I2SR);
writeb(I2CR_IEN, i2c_imx->base + IMX_I2C_I2CR);
+
+ /* Wait controller to be stable */
+ udelay(50);
+
/* Start I2C transaction */
temp = readb(i2c_imx->base + IMX_I2C_I2CR);
temp |= I2CR_MSTA;
writeb(temp, i2c_imx->base + IMX_I2C_I2CR);
+ result = i2c_imx_bus_busy(i2c_imx, 1);
+ if (result)
+ return result;
+ i2c_imx->stopped = 0;
+
temp |= I2CR_IIEN | I2CR_MTX | I2CR_TXAK;
writeb(temp, i2c_imx->base + IMX_I2C_I2CR);
+ return result;
}
static void i2c_imx_stop(struct imx_i2c_struct *i2c_imx)
{
unsigned int temp = 0;
- /* Stop I2C transaction */
- dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__);
- temp = readb(i2c_imx->base + IMX_I2C_I2CR);
- temp &= ~I2CR_MSTA;
- writeb(temp, i2c_imx->base + IMX_I2C_I2CR);
- /* setup chip registers to defaults */
- writeb(I2CR_IEN, i2c_imx->base + IMX_I2C_I2CR);
- writeb(0, i2c_imx->base + IMX_I2C_I2SR);
- /*
- * This delay caused by an i.MXL hardware bug.
- * If no (or too short) delay, no "STOP" bit will be generated.
- */
- udelay(i2c_imx->disable_delay);
+ if (!i2c_imx->stopped) {
+ /* Stop I2C transaction */
+ dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__);
+ temp = readb(i2c_imx->base + IMX_I2C_I2CR);
+ temp &= ~(I2CR_MSTA | I2CR_MTX);
+ writeb(temp, i2c_imx->base + IMX_I2C_I2CR);
+ i2c_imx->stopped = 1;
+ }
+ if (cpu_is_mx1()) {
+ /*
+ * This delay caused by an i.MXL hardware bug.
+ * If no (or too short) delay, no "STOP" bit will be generated.
+ */
+ udelay(i2c_imx->disable_delay);
+ }
+
+ if (!i2c_imx->stopped)
+ i2c_imx_bus_busy(i2c_imx, 0);
+
/* Disable I2C controller */
writeb(0, i2c_imx->base + IMX_I2C_I2CR);
+ clk_disable(i2c_imx->clk);
}
static void __init i2c_imx_set_clk(struct imx_i2c_struct *i2c_imx,
@@ -233,8 +261,8 @@ static void __init i2c_imx_set_clk(struct imx_i2c_struct *i2c_imx,
else
for (i = 0; i2c_clk_div[i][0] < div; i++);
- /* Write divider value to register */
- writeb(i2c_clk_div[i][1], i2c_imx->base + IMX_I2C_IFDR);
+ /* Store divider value */
+ i2c_imx->ifdr = i2c_clk_div[i][1];
/*
* There dummy delay is calculated.
@@ -341,11 +369,15 @@ static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs)
if (result)
return result;
if (i == (msgs->len - 1)) {
+ /* It must generate STOP before read I2DR to prevent
+ controller from generating another clock cycle */
dev_dbg(&i2c_imx->adapter.dev,
"<%s> clear MSTA\n", __func__);
temp = readb(i2c_imx->base + IMX_I2C_I2CR);
- temp &= ~I2CR_MSTA;
+ temp &= ~(I2CR_MSTA | I2CR_MTX);
writeb(temp, i2c_imx->base + IMX_I2C_I2CR);
+ i2c_imx_bus_busy(i2c_imx, 0);
+ i2c_imx->stopped = 1;
} else if (i == (msgs->len - 2)) {
dev_dbg(&i2c_imx->adapter.dev,
"<%s> set TXAK\n", __func__);
@@ -370,14 +402,11 @@ static int i2c_imx_xfer(struct i2c_adapter *adapter,
dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__);
- /* Check if i2c bus is not busy */
- result = i2c_imx_bus_busy(i2c_imx);
+ /* Start I2C transfer */
+ result = i2c_imx_start(i2c_imx);
if (result)
goto fail0;
- /* Start I2C transfer */
- i2c_imx_start(i2c_imx);
-
/* read/write data */
for (i = 0; i < num; i++) {
if (i) {
@@ -386,6 +415,9 @@ static int i2c_imx_xfer(struct i2c_adapter *adapter,
temp = readb(i2c_imx->base + IMX_I2C_I2CR);
temp |= I2CR_RSTA;
writeb(temp, i2c_imx->base + IMX_I2C_I2CR);
+ result = i2c_imx_bus_busy(i2c_imx, 1);
+ if (result)
+ goto fail0;
}
dev_dbg(&i2c_imx->adapter.dev,
"<%s> transfer message: %d\n", __func__, i);
@@ -500,7 +532,6 @@ static int __init i2c_imx_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "can't get I2C clock\n");
goto fail3;
}
- clk_enable(i2c_imx->clk);
/* Request IRQ */
ret = request_irq(i2c_imx->irq, i2c_imx_isr, 0, pdev->name, i2c_imx);
@@ -549,7 +580,6 @@ static int __init i2c_imx_probe(struct platform_device *pdev)
fail5:
free_irq(i2c_imx->irq, i2c_imx);
fail4:
- clk_disable(i2c_imx->clk);
clk_put(i2c_imx->clk);
fail3:
release_mem_region(i2c_imx->res->start, resource_size(res));
@@ -586,8 +616,6 @@ static int __exit i2c_imx_remove(struct platform_device *pdev)
if (pdata && pdata->exit)
pdata->exit(&pdev->dev);
- /* Disable I2C clock */
- clk_disable(i2c_imx->clk);
clk_put(i2c_imx->clk);
release_mem_region(i2c_imx->res->start, resource_size(i2c_imx->res));
diff --git a/drivers/i2c/busses/i2c-iop3xx.c b/drivers/i2c/busses/i2c-iop3xx.c
index a75c75e77b9..5901707fc66 100644
--- a/drivers/i2c/busses/i2c-iop3xx.c
+++ b/drivers/i2c/busses/i2c-iop3xx.c
@@ -56,12 +56,6 @@ iic_cook_addr(struct i2c_msg *msg)
if (msg->flags & I2C_M_RD)
addr |= 1;
- /*
- * Read or Write?
- */
- if (msg->flags & I2C_M_REV_DIR_ADDR)
- addr ^= 1;
-
return addr;
}
diff --git a/drivers/i2c/busses/i2c-isch.c b/drivers/i2c/busses/i2c-isch.c
index 9f6b8e0f863..dba6eb053e2 100644
--- a/drivers/i2c/busses/i2c-isch.c
+++ b/drivers/i2c/busses/i2c-isch.c
@@ -281,7 +281,7 @@ static int __devinit sch_probe(struct pci_dev *dev,
return -ENODEV;
}
if (acpi_check_region(sch_smba, SMBIOSIZE, sch_driver.name))
- return -EBUSY;
+ return -ENODEV;
if (!request_region(sch_smba, SMBIOSIZE, sch_driver.name)) {
dev_err(&dev->dev, "SMBus region 0x%x already in use!\n",
sch_smba);
diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c
index d325e86e310..f627001108b 100644
--- a/drivers/i2c/busses/i2c-mpc.c
+++ b/drivers/i2c/busses/i2c-mpc.c
@@ -365,9 +365,6 @@ static int mpc_write(struct mpc_i2c *i2c, int target,
unsigned timeout = i2c->adap.timeout;
u32 flags = restart ? CCR_RSTA : 0;
- /* Start with MEN */
- if (!restart)
- writeccr(i2c, CCR_MEN);
/* Start as master */
writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_MTX | flags);
/* Write target byte */
@@ -396,9 +393,6 @@ static int mpc_read(struct mpc_i2c *i2c, int target,
int i, result;
u32 flags = restart ? CCR_RSTA : 0;
- /* Start with MEN */
- if (!restart)
- writeccr(i2c, CCR_MEN);
/* Switch to read - restart */
writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_MTX | flags);
/* Write target address byte - this time with the read flag set */
@@ -425,9 +419,9 @@ static int mpc_read(struct mpc_i2c *i2c, int target,
/* Generate txack on next to last byte */
if (i == length - 2)
writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_TXAK);
- /* Generate stop on last byte */
+ /* Do not generate stop on last byte */
if (i == length - 1)
- writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_TXAK);
+ writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_MTX);
data[i] = readb(i2c->base + MPC_I2C_DR);
}
diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c
index bbab0e16663..ed387ffa473 100644
--- a/drivers/i2c/busses/i2c-mv64xxx.c
+++ b/drivers/i2c/busses/i2c-mv64xxx.c
@@ -338,9 +338,6 @@ mv64xxx_i2c_prepare_for_io(struct mv64xxx_i2c_data *drv_data,
if (msg->flags & I2C_M_RD)
dir = 1;
- if (msg->flags & I2C_M_REV_DIR_ADDR)
- dir ^= 1;
-
if (msg->flags & I2C_M_TEN) {
drv_data->addr1 = 0xf0 | (((u32)msg->addr & 0x300) >> 7) | dir;
drv_data->addr2 = (u32)msg->addr & 0xff;
diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c
index a782c7a08f9..1e245e9cad3 100644
--- a/drivers/i2c/busses/i2c-piix4.c
+++ b/drivers/i2c/busses/i2c-piix4.c
@@ -22,7 +22,7 @@
Intel PIIX4, 440MX
Serverworks OSB4, CSB5, CSB6, HT-1000, HT-1100
ATI IXP200, IXP300, IXP400, SB600, SB700, SB800
- AMD SB900
+ AMD Hudson-2
SMSC Victory66
Note: we assume there can only be one device, with one SMBus interface.
@@ -169,7 +169,7 @@ static int __devinit piix4_setup(struct pci_dev *PIIX4_dev,
}
if (acpi_check_region(piix4_smba, SMBIOSIZE, piix4_driver.name))
- return -EBUSY;
+ return -ENODEV;
if (!request_region(piix4_smba, SMBIOSIZE, piix4_driver.name)) {
dev_err(&PIIX4_dev->dev, "SMBus region 0x%x already in use!\n",
@@ -233,9 +233,9 @@ static int __devinit piix4_setup_sb800(struct pci_dev *PIIX4_dev,
unsigned short smba_idx = 0xcd6;
u8 smba_en_lo, smba_en_hi, i2ccfg, i2ccfg_offset = 0x10, smb_en = 0x2c;
- /* SB800 SMBus does not support forcing address */
+ /* SB800 and later SMBus does not support forcing address */
if (force || force_addr) {
- dev_err(&PIIX4_dev->dev, "SB800 SMBus does not support "
+ dev_err(&PIIX4_dev->dev, "SMBus does not support "
"forcing address!\n");
return -EINVAL;
}
@@ -260,7 +260,7 @@ static int __devinit piix4_setup_sb800(struct pci_dev *PIIX4_dev,
piix4_smba = ((smba_en_hi << 8) | smba_en_lo) & 0xffe0;
if (acpi_check_region(piix4_smba, SMBIOSIZE, piix4_driver.name))
- return -EBUSY;
+ return -ENODEV;
if (!request_region(piix4_smba, SMBIOSIZE, piix4_driver.name)) {
dev_err(&PIIX4_dev->dev, "SMBus region 0x%x already in use!\n",
@@ -480,7 +480,7 @@ static struct pci_device_id piix4_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP300_SMBUS) },
{ 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_SB900_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_HUDSON2_SMBUS) },
{ PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS,
PCI_DEVICE_ID_SERVERWORKS_OSB4) },
{ PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS,
diff --git a/drivers/i2c/busses/i2c-pnx.c b/drivers/i2c/busses/i2c-pnx.c
index 6ff6c20f1e7..fbab6846ae6 100644
--- a/drivers/i2c/busses/i2c-pnx.c
+++ b/drivers/i2c/busses/i2c-pnx.c
@@ -19,7 +19,9 @@
#include <linux/completion.h>
#include <linux/platform_device.h>
#include <linux/i2c-pnx.h>
+#include <linux/io.h>
#include <mach/hardware.h>
+#include <mach/i2c.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
@@ -54,6 +56,9 @@ static inline void i2c_pnx_arm_timer(struct i2c_adapter *adap)
struct timer_list *timer = &data->mif.timer;
int expires = I2C_PNX_TIMEOUT / (1000 / HZ);
+ if (expires <= 1)
+ expires = 2;
+
del_timer_sync(timer);
dev_dbg(&adap->dev, "Timer armed at %lu plus %u jiffies.\n",
@@ -645,7 +650,7 @@ static int __devinit i2c_pnx_probe(struct platform_device *pdev)
return 0;
out_irq:
- free_irq(alg_data->irq, alg_data);
+ free_irq(alg_data->irq, i2c_pnx->adapter);
out_clock:
i2c_pnx->set_clock_stop(pdev);
out_unmap:
@@ -664,7 +669,7 @@ static int __devexit i2c_pnx_remove(struct platform_device *pdev)
struct i2c_adapter *adap = i2c_pnx->adapter;
struct i2c_pnx_algo_data *alg_data = adap->algo_data;
- free_irq(alg_data->irq, alg_data);
+ free_irq(alg_data->irq, i2c_pnx->adapter);
i2c_del_adapter(adap);
i2c_pnx->set_clock_stop(pdev);
iounmap((void *)alg_data->ioaddr);
diff --git a/drivers/i2c/busses/i2c-powermac.c b/drivers/i2c/busses/i2c-powermac.c
index 3c9d71f6018..1c440a70ec6 100644
--- a/drivers/i2c/busses/i2c-powermac.c
+++ b/drivers/i2c/busses/i2c-powermac.c
@@ -49,48 +49,38 @@ static s32 i2c_powermac_smbus_xfer( struct i2c_adapter* adap,
int rc = 0;
int read = (read_write == I2C_SMBUS_READ);
int addrdir = (addr << 1) | read;
+ int mode, subsize, len;
+ u32 subaddr;
+ u8 *buf;
u8 local[2];
- rc = pmac_i2c_open(bus, 0);
- if (rc)
- return rc;
+ if (size == I2C_SMBUS_QUICK || size == I2C_SMBUS_BYTE) {
+ mode = pmac_i2c_mode_std;
+ subsize = 0;
+ subaddr = 0;
+ } else {
+ mode = read ? pmac_i2c_mode_combined : pmac_i2c_mode_stdsub;
+ subsize = 1;
+ subaddr = command;
+ }
switch (size) {
case I2C_SMBUS_QUICK:
- rc = pmac_i2c_setmode(bus, pmac_i2c_mode_std);
- if (rc)
- goto bail;
- rc = pmac_i2c_xfer(bus, addrdir, 0, 0, NULL, 0);
+ buf = NULL;
+ len = 0;
break;
case I2C_SMBUS_BYTE:
- rc = pmac_i2c_setmode(bus, pmac_i2c_mode_std);
- if (rc)
- goto bail;
- rc = pmac_i2c_xfer(bus, addrdir, 0, 0, &data->byte, 1);
- break;
case I2C_SMBUS_BYTE_DATA:
- rc = pmac_i2c_setmode(bus, read ?
- pmac_i2c_mode_combined :
- pmac_i2c_mode_stdsub);
- if (rc)
- goto bail;
- rc = pmac_i2c_xfer(bus, addrdir, 1, command, &data->byte, 1);
+ buf = &data->byte;
+ len = 1;
break;
case I2C_SMBUS_WORD_DATA:
- rc = pmac_i2c_setmode(bus, read ?
- pmac_i2c_mode_combined :
- pmac_i2c_mode_stdsub);
- if (rc)
- goto bail;
if (!read) {
local[0] = data->word & 0xff;
local[1] = (data->word >> 8) & 0xff;
}
- rc = pmac_i2c_xfer(bus, addrdir, 1, command, local, 2);
- if (rc == 0 && read) {
- data->word = ((u16)local[1]) << 8;
- data->word |= local[0];
- }
+ buf = local;
+ len = 2;
break;
/* Note that these are broken vs. the expected smbus API where
@@ -105,28 +95,44 @@ static s32 i2c_powermac_smbus_xfer( struct i2c_adapter* adap,
* a repeat start/addr phase (but not stop in between)
*/
case I2C_SMBUS_BLOCK_DATA:
- rc = pmac_i2c_setmode(bus, read ?
- pmac_i2c_mode_combined :
- pmac_i2c_mode_stdsub);
- if (rc)
- goto bail;
- rc = pmac_i2c_xfer(bus, addrdir, 1, command, data->block,
- data->block[0] + 1);
-
+ buf = data->block;
+ len = data->block[0] + 1;
break;
case I2C_SMBUS_I2C_BLOCK_DATA:
- rc = pmac_i2c_setmode(bus, read ?
- pmac_i2c_mode_combined :
- pmac_i2c_mode_stdsub);
- if (rc)
- goto bail;
- rc = pmac_i2c_xfer(bus, addrdir, 1, command,
- &data->block[1], data->block[0]);
+ buf = &data->block[1];
+ len = data->block[0];
break;
default:
- rc = -EINVAL;
+ return -EINVAL;
+ }
+
+ rc = pmac_i2c_open(bus, 0);
+ if (rc) {
+ dev_err(&adap->dev, "Failed to open I2C, err %d\n", rc);
+ return rc;
+ }
+
+ rc = pmac_i2c_setmode(bus, mode);
+ if (rc) {
+ dev_err(&adap->dev, "Failed to set I2C mode %d, err %d\n",
+ mode, rc);
+ goto bail;
}
+
+ rc = pmac_i2c_xfer(bus, addrdir, subsize, subaddr, buf, len);
+ if (rc) {
+ dev_err(&adap->dev,
+ "I2C transfer at 0x%02x failed, size %d, err %d\n",
+ addrdir >> 1, size, rc);
+ goto bail;
+ }
+
+ if (size == I2C_SMBUS_WORD_DATA && read) {
+ data->word = ((u16)local[1]) << 8;
+ data->word |= local[0];
+ }
+
bail:
pmac_i2c_close(bus);
return rc;
@@ -146,20 +152,33 @@ static int i2c_powermac_master_xfer( struct i2c_adapter *adap,
int read;
int addrdir;
+ if (num != 1) {
+ dev_err(&adap->dev,
+ "Multi-message I2C transactions not supported\n");
+ return -EOPNOTSUPP;
+ }
+
if (msgs->flags & I2C_M_TEN)
return -EINVAL;
read = (msgs->flags & I2C_M_RD) != 0;
addrdir = (msgs->addr << 1) | read;
- if (msgs->flags & I2C_M_REV_DIR_ADDR)
- addrdir ^= 1;
rc = pmac_i2c_open(bus, 0);
- if (rc)
+ if (rc) {
+ dev_err(&adap->dev, "Failed to open I2C, err %d\n", rc);
return rc;
+ }
rc = pmac_i2c_setmode(bus, pmac_i2c_mode_std);
- if (rc)
+ if (rc) {
+ dev_err(&adap->dev, "Failed to set I2C mode %d, err %d\n",
+ pmac_i2c_mode_std, rc);
goto bail;
+ }
rc = pmac_i2c_xfer(bus, addrdir, 0, 0, msgs->buf, msgs->len);
+ if (rc < 0)
+ dev_err(&adap->dev, "I2C %s 0x%02x failed, err %d\n",
+ addrdir & 1 ? "read from" : "write to", addrdir >> 1,
+ rc);
bail:
pmac_i2c_close(bus);
return rc < 0 ? rc : 1;
@@ -183,19 +202,16 @@ static const struct i2c_algorithm i2c_powermac_algorithm = {
static int __devexit i2c_powermac_remove(struct platform_device *dev)
{
struct i2c_adapter *adapter = platform_get_drvdata(dev);
- struct pmac_i2c_bus *bus = i2c_get_adapdata(adapter);
int rc;
rc = i2c_del_adapter(adapter);
- pmac_i2c_detach_adapter(bus, adapter);
- i2c_set_adapdata(adapter, NULL);
/* We aren't that prepared to deal with this... */
if (rc)
printk(KERN_WARNING
"i2c-powermac.c: Failed to remove bus %s !\n",
adapter->name);
platform_set_drvdata(dev, NULL);
- kfree(adapter);
+ memset(adapter, 0, sizeof(*adapter));
return 0;
}
@@ -206,12 +222,12 @@ static int __devinit i2c_powermac_probe(struct platform_device *dev)
struct pmac_i2c_bus *bus = dev->dev.platform_data;
struct device_node *parent = NULL;
struct i2c_adapter *adapter;
- char name[32];
const char *basename;
int rc;
if (bus == NULL)
return -EINVAL;
+ adapter = pmac_i2c_get_adapter(bus);
/* Ok, now we need to make up a name for the interface that will
* match what we used to do in the past, that is basically the
@@ -237,29 +253,22 @@ static int __devinit i2c_powermac_probe(struct platform_device *dev)
default:
return -EINVAL;
}
- snprintf(name, 32, "%s %d", basename, pmac_i2c_get_channel(bus));
+ snprintf(adapter->name, sizeof(adapter->name), "%s %d", basename,
+ pmac_i2c_get_channel(bus));
of_node_put(parent);
- adapter = kzalloc(sizeof(struct i2c_adapter), GFP_KERNEL);
- if (adapter == NULL) {
- printk(KERN_ERR "i2c-powermac: can't allocate inteface !\n");
- return -ENOMEM;
- }
platform_set_drvdata(dev, adapter);
- strcpy(adapter->name, name);
adapter->algo = &i2c_powermac_algorithm;
i2c_set_adapdata(adapter, bus);
adapter->dev.parent = &dev->dev;
- pmac_i2c_attach_adapter(bus, adapter);
rc = i2c_add_adapter(adapter);
if (rc) {
printk(KERN_ERR "i2c-powermac: Adapter %s registration "
- "failed\n", name);
- i2c_set_adapdata(adapter, NULL);
- pmac_i2c_detach_adapter(bus, adapter);
+ "failed\n", adapter->name);
+ memset(adapter, 0, sizeof(*adapter));
}
- printk(KERN_INFO "PowerMac i2c bus %s registered\n", name);
+ printk(KERN_INFO "PowerMac i2c bus %s registered\n", adapter->name);
if (!strncmp(basename, "uni-n", 5)) {
struct device_node *np;
diff --git a/drivers/i2c/busses/i2c-sis5595.c b/drivers/i2c/busses/i2c-sis5595.c
index 139f0c7f12a..844569f7d8b 100644
--- a/drivers/i2c/busses/i2c-sis5595.c
+++ b/drivers/i2c/busses/i2c-sis5595.c
@@ -142,7 +142,7 @@ static void sis5595_write(u8 reg, u8 data)
outb(data, sis5595_base + SMB_DAT);
}
-static int sis5595_setup(struct pci_dev *SIS5595_dev)
+static int __devinit sis5595_setup(struct pci_dev *SIS5595_dev)
{
u16 a;
u8 val;
diff --git a/drivers/i2c/busses/i2c-sis630.c b/drivers/i2c/busses/i2c-sis630.c
index 70ca41e90e5..68cff7af701 100644
--- a/drivers/i2c/busses/i2c-sis630.c
+++ b/drivers/i2c/busses/i2c-sis630.c
@@ -389,7 +389,7 @@ static u32 sis630_func(struct i2c_adapter *adapter)
I2C_FUNC_SMBUS_BLOCK_DATA;
}
-static int sis630_setup(struct pci_dev *sis630_dev)
+static int __devinit sis630_setup(struct pci_dev *sis630_dev)
{
unsigned char b;
struct pci_dev *dummy = NULL;
diff --git a/drivers/i2c/busses/i2c-sis96x.c b/drivers/i2c/busses/i2c-sis96x.c
index 8295885b2fd..1649963b00d 100644
--- a/drivers/i2c/busses/i2c-sis96x.c
+++ b/drivers/i2c/busses/i2c-sis96x.c
@@ -280,7 +280,7 @@ static int __devinit sis96x_probe(struct pci_dev *dev,
retval = acpi_check_resource_conflict(&dev->resource[SIS96x_BAR]);
if (retval)
- return retval;
+ return -ENODEV;
/* Everything is happy, let's grab the memory and set things up. */
if (!request_region(sis96x_smbus_base, SMB_IOSIZE,
diff --git a/drivers/i2c/busses/i2c-stub.c b/drivers/i2c/busses/i2c-stub.c
index 1b7b2af9403..0c770eabe85 100644
--- a/drivers/i2c/busses/i2c-stub.c
+++ b/drivers/i2c/busses/i2c-stub.c
@@ -35,6 +35,10 @@ module_param_array(chip_addr, ushort, NULL, S_IRUGO);
MODULE_PARM_DESC(chip_addr,
"Chip addresses (up to 10, between 0x03 and 0x77)");
+static unsigned long functionality = ~0UL;
+module_param(functionality, ulong, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(functionality, "Override functionality bitfield");
+
struct stub_chip {
u8 pointer;
u16 words[256]; /* Byte operations use the LSB as per SMBus
@@ -48,7 +52,7 @@ static s32 stub_xfer(struct i2c_adapter * adap, u16 addr, unsigned short flags,
char read_write, u8 command, int size, union i2c_smbus_data * data)
{
s32 ret;
- int i;
+ int i, len;
struct stub_chip *chip = NULL;
/* Search for the right chip */
@@ -118,6 +122,29 @@ static s32 stub_xfer(struct i2c_adapter * adap, u16 addr, unsigned short flags,
ret = 0;
break;
+ case I2C_SMBUS_I2C_BLOCK_DATA:
+ len = data->block[0];
+ if (read_write == I2C_SMBUS_WRITE) {
+ for (i = 0; i < len; i++) {
+ chip->words[command + i] &= 0xff00;
+ chip->words[command + i] |= data->block[1 + i];
+ }
+ dev_dbg(&adap->dev, "i2c block data - addr 0x%02x, "
+ "wrote %d bytes at 0x%02x.\n",
+ addr, len, command);
+ } else {
+ for (i = 0; i < len; i++) {
+ data->block[1 + i] =
+ chip->words[command + i] & 0xff;
+ }
+ dev_dbg(&adap->dev, "i2c block data - addr 0x%02x, "
+ "read %d bytes at 0x%02x.\n",
+ addr, len, command);
+ }
+
+ ret = 0;
+ break;
+
default:
dev_dbg(&adap->dev, "Unsupported I2C/SMBus command\n");
ret = -EOPNOTSUPP;
@@ -129,8 +156,9 @@ static s32 stub_xfer(struct i2c_adapter * adap, u16 addr, unsigned short flags,
static u32 stub_func(struct i2c_adapter *adapter)
{
- return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
- I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA;
+ return (I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
+ I2C_FUNC_SMBUS_I2C_BLOCK) & functionality;
}
static const struct i2c_algorithm smbus_algorithm = {
diff --git a/drivers/i2c/busses/i2c-viapro.c b/drivers/i2c/busses/i2c-viapro.c
index 54d810a4d00..e4b1543015a 100644
--- a/drivers/i2c/busses/i2c-viapro.c
+++ b/drivers/i2c/busses/i2c-viapro.c
@@ -365,7 +365,7 @@ static int __devinit vt596_probe(struct pci_dev *pdev,
found:
error = acpi_check_region(vt596_smba, 8, vt596_driver.name);
if (error)
- return error;
+ return -ENODEV;
if (!request_region(vt596_smba, 8, vt596_driver.name)) {
dev_err(&pdev->dev, "SMBus region 0x%x already in use!\n",
diff --git a/drivers/i2c/busses/i2c-voodoo3.c b/drivers/i2c/busses/i2c-voodoo3.c
deleted file mode 100644
index 7663d57833a..00000000000
--- a/drivers/i2c/busses/i2c-voodoo3.c
+++ /dev/null
@@ -1,248 +0,0 @@
-/*
- Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl>,
- Philip Edelbrock <phil@netroedge.com>,
- Ralph Metzler <rjkm@thp.uni-koeln.de>, and
- Mark D. Studebaker <mdsxyz123@yahoo.com>
-
- Based on code written by Ralph Metzler <rjkm@thp.uni-koeln.de> and
- Simon Vogl
-
- 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.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- 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.
-*/
-
-/* This interfaces to the I2C bus of the Voodoo3 to gain access to
- the BT869 and possibly other I2C devices. */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/i2c.h>
-#include <linux/i2c-algo-bit.h>
-#include <asm/io.h>
-
-/* the only registers we use */
-#define REG 0x78
-#define REG2 0x70
-
-/* bit locations in the register */
-#define DDC_ENAB 0x00040000
-#define DDC_SCL_OUT 0x00080000
-#define DDC_SDA_OUT 0x00100000
-#define DDC_SCL_IN 0x00200000
-#define DDC_SDA_IN 0x00400000
-#define I2C_ENAB 0x00800000
-#define I2C_SCL_OUT 0x01000000
-#define I2C_SDA_OUT 0x02000000
-#define I2C_SCL_IN 0x04000000
-#define I2C_SDA_IN 0x08000000
-
-/* initialization states */
-#define INIT2 0x2
-#define INIT3 0x4
-
-/* delays */
-#define CYCLE_DELAY 10
-#define TIMEOUT (HZ / 2)
-
-
-static void __iomem *ioaddr;
-
-/* The voo GPIO registers don't have individual masks for each bit
- so we always have to read before writing. */
-
-static void bit_vooi2c_setscl(void *data, int val)
-{
- unsigned int r;
- r = readl(ioaddr + REG);
- if (val)
- r |= I2C_SCL_OUT;
- else
- r &= ~I2C_SCL_OUT;
- writel(r, ioaddr + REG);
- readl(ioaddr + REG); /* flush posted write */
-}
-
-static void bit_vooi2c_setsda(void *data, int val)
-{
- unsigned int r;
- r = readl(ioaddr + REG);
- if (val)
- r |= I2C_SDA_OUT;
- else
- r &= ~I2C_SDA_OUT;
- writel(r, ioaddr + REG);
- readl(ioaddr + REG); /* flush posted write */
-}
-
-/* The GPIO pins are open drain, so the pins always remain outputs.
- We rely on the i2c-algo-bit routines to set the pins high before
- reading the input from other chips. */
-
-static int bit_vooi2c_getscl(void *data)
-{
- return (0 != (readl(ioaddr + REG) & I2C_SCL_IN));
-}
-
-static int bit_vooi2c_getsda(void *data)
-{
- return (0 != (readl(ioaddr + REG) & I2C_SDA_IN));
-}
-
-static void bit_vooddc_setscl(void *data, int val)
-{
- unsigned int r;
- r = readl(ioaddr + REG);
- if (val)
- r |= DDC_SCL_OUT;
- else
- r &= ~DDC_SCL_OUT;
- writel(r, ioaddr + REG);
- readl(ioaddr + REG); /* flush posted write */
-}
-
-static void bit_vooddc_setsda(void *data, int val)
-{
- unsigned int r;
- r = readl(ioaddr + REG);
- if (val)
- r |= DDC_SDA_OUT;
- else
- r &= ~DDC_SDA_OUT;
- writel(r, ioaddr + REG);
- readl(ioaddr + REG); /* flush posted write */
-}
-
-static int bit_vooddc_getscl(void *data)
-{
- return (0 != (readl(ioaddr + REG) & DDC_SCL_IN));
-}
-
-static int bit_vooddc_getsda(void *data)
-{
- return (0 != (readl(ioaddr + REG) & DDC_SDA_IN));
-}
-
-static int config_v3(struct pci_dev *dev)
-{
- unsigned long cadr;
-
- /* map Voodoo3 memory */
- cadr = dev->resource[0].start;
- cadr &= PCI_BASE_ADDRESS_MEM_MASK;
- ioaddr = ioremap_nocache(cadr, 0x1000);
- if (ioaddr) {
- writel(0x8160, ioaddr + REG2);
- writel(0xcffc0020, ioaddr + REG);
- dev_info(&dev->dev, "Using Banshee/Voodoo3 I2C device at %p\n", ioaddr);
- return 0;
- }
- return -ENODEV;
-}
-
-static struct i2c_algo_bit_data voo_i2c_bit_data = {
- .setsda = bit_vooi2c_setsda,
- .setscl = bit_vooi2c_setscl,
- .getsda = bit_vooi2c_getsda,
- .getscl = bit_vooi2c_getscl,
- .udelay = CYCLE_DELAY,
- .timeout = TIMEOUT
-};
-
-static struct i2c_adapter voodoo3_i2c_adapter = {
- .owner = THIS_MODULE,
- .name = "I2C Voodoo3/Banshee adapter",
- .algo_data = &voo_i2c_bit_data,
-};
-
-static struct i2c_algo_bit_data voo_ddc_bit_data = {
- .setsda = bit_vooddc_setsda,
- .setscl = bit_vooddc_setscl,
- .getsda = bit_vooddc_getsda,
- .getscl = bit_vooddc_getscl,
- .udelay = CYCLE_DELAY,
- .timeout = TIMEOUT
-};
-
-static struct i2c_adapter voodoo3_ddc_adapter = {
- .owner = THIS_MODULE,
- .class = I2C_CLASS_DDC,
- .name = "DDC Voodoo3/Banshee adapter",
- .algo_data = &voo_ddc_bit_data,
-};
-
-static struct pci_device_id voodoo3_ids[] __devinitdata = {
- { PCI_DEVICE(PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_VOODOO3) },
- { PCI_DEVICE(PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_BANSHEE) },
- { 0, }
-};
-
-MODULE_DEVICE_TABLE (pci, voodoo3_ids);
-
-static int __devinit voodoo3_probe(struct pci_dev *dev, const struct pci_device_id *id)
-{
- int retval;
-
- retval = config_v3(dev);
- if (retval)
- return retval;
-
- /* set up the sysfs linkage to our parent device */
- voodoo3_i2c_adapter.dev.parent = &dev->dev;
- voodoo3_ddc_adapter.dev.parent = &dev->dev;
-
- retval = i2c_bit_add_bus(&voodoo3_i2c_adapter);
- if (retval)
- return retval;
- retval = i2c_bit_add_bus(&voodoo3_ddc_adapter);
- if (retval)
- i2c_del_adapter(&voodoo3_i2c_adapter);
- return retval;
-}
-
-static void __devexit voodoo3_remove(struct pci_dev *dev)
-{
- i2c_del_adapter(&voodoo3_i2c_adapter);
- i2c_del_adapter(&voodoo3_ddc_adapter);
- iounmap(ioaddr);
-}
-
-static struct pci_driver voodoo3_driver = {
- .name = "voodoo3_smbus",
- .id_table = voodoo3_ids,
- .probe = voodoo3_probe,
- .remove = __devexit_p(voodoo3_remove),
-};
-
-static int __init i2c_voodoo3_init(void)
-{
- return pci_register_driver(&voodoo3_driver);
-}
-
-static void __exit i2c_voodoo3_exit(void)
-{
- pci_unregister_driver(&voodoo3_driver);
-}
-
-
-MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, "
- "Philip Edelbrock <phil@netroedge.com>, "
- "Ralph Metzler <rjkm@thp.uni-koeln.de>, "
- "and Mark D. Studebaker <mdsxyz123@yahoo.com>");
-MODULE_DESCRIPTION("Voodoo3 I2C/SMBus driver");
-MODULE_LICENSE("GPL");
-
-module_init(i2c_voodoo3_init);
-module_exit(i2c_voodoo3_exit);