From a0832798c05241f15e793805b6024919c07b8292 Mon Sep 17 00:00:00 2001 From: Tzachi Perelstein Date: Mon, 12 Nov 2007 19:38:51 +0200 Subject: [I2C] Split mv643xx I2C platform support The motivation for this change is to allow other chips, like the Marvell Orion ARM SoC family, to use the existing i2c-mv64xxx driver. Signed-off-by: Tzachi Perelstein Acked-by: Nicolas Pitre Acked-by: Dale Farnsworth Acked-by: Mark A. Greer Acked-by: Jean Delvare --- drivers/i2c/busses/Kconfig | 2 +- drivers/i2c/busses/i2c-mv64xxx.c | 31 +++++++++++++++++-------------- 2 files changed, 18 insertions(+), 15 deletions(-) (limited to 'drivers/i2c/busses') diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index c466c6cfc2e5..b148bf0ec6b7 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -648,7 +648,7 @@ config I2C_PCA_ISA config I2C_MV64XXX tristate "Marvell mv64xxx I2C Controller" - depends on MV64X60 && EXPERIMENTAL + depends on (MV64X60 || ARCH_ORION) && EXPERIMENTAL help If you say yes to this option, support will be included for the built-in I2C interface on the Marvell 64xxx line of host bridges. diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c index bb7bf68a7fb6..cdd1ef99fcff 100644 --- a/drivers/i2c/busses/i2c-mv64xxx.c +++ b/drivers/i2c/busses/i2c-mv64xxx.c @@ -1,6 +1,6 @@ /* - * Driver for the i2c controller on the Marvell line of host bridges for MIPS - * and PPC (e.g, gt642[46]0, mv643[46]0, mv644[46]0). + * Driver for the i2c controller on the Marvell line of host bridges + * (e.g, gt642[46]0, mv643[46]0, mv644[46]0, and Orion SoC family). * * Author: Mark A. Greer * @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include @@ -86,6 +86,7 @@ struct mv64xxx_i2c_data { u32 cntl_bits; void __iomem *reg_base; u32 reg_base_p; + u32 reg_size; u32 addr1; u32 addr2; u32 bytes_left; @@ -463,17 +464,20 @@ static int __devinit mv64xxx_i2c_map_regs(struct platform_device *pd, struct mv64xxx_i2c_data *drv_data) { - struct resource *r; + int size; + struct resource *r = platform_get_resource(pd, IORESOURCE_MEM, 0); - if ((r = platform_get_resource(pd, IORESOURCE_MEM, 0)) && - request_mem_region(r->start, MV64XXX_I2C_REG_BLOCK_SIZE, - drv_data->adapter.name)) { + if (!r) + return -ENODEV; - drv_data->reg_base = ioremap(r->start, - MV64XXX_I2C_REG_BLOCK_SIZE); - drv_data->reg_base_p = r->start; - } else - return -ENOMEM; + size = r->end - r->start + 1; + + if (!request_mem_region(r->start, size, drv_data->adapter.name)) + return -EBUSY; + + drv_data->reg_base = ioremap(r->start, size); + drv_data->reg_base_p = r->start; + drv_data->reg_size = size; return 0; } @@ -483,8 +487,7 @@ mv64xxx_i2c_unmap_regs(struct mv64xxx_i2c_data *drv_data) { if (drv_data->reg_base) { iounmap(drv_data->reg_base); - release_mem_region(drv_data->reg_base_p, - MV64XXX_I2C_REG_BLOCK_SIZE); + release_mem_region(drv_data->reg_base_p, drv_data->reg_size); } drv_data->reg_base = NULL; -- cgit v1.2.3 From 2f0a8df40ff008822e5570b3323c56622cd92c95 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 22 Nov 2007 16:58:08 +0100 Subject: [I2C] i2c-mv64xxx: Don't set i2c_adapter.retries I2C adapter drivers are supposed to handle retries on nack by themselves if they do, so there's no point in setting .retries if they don't. As this retry mechanism is going away (at least in its current form), clean this up now so that we don't get build failures later. Signed-off-by: Jean Delvare Acked-by: Mark A. Greer --- drivers/i2c/busses/i2c-mv64xxx.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/i2c/busses') diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c index cdd1ef99fcff..036e6a883e67 100644 --- a/drivers/i2c/busses/i2c-mv64xxx.c +++ b/drivers/i2c/busses/i2c-mv64xxx.c @@ -532,7 +532,6 @@ mv64xxx_i2c_probe(struct platform_device *pd) drv_data->adapter.owner = THIS_MODULE; drv_data->adapter.class = I2C_CLASS_HWMON; drv_data->adapter.timeout = pdata->timeout; - drv_data->adapter.retries = pdata->retries; drv_data->adapter.nr = pd->id; platform_set_drvdata(pd, drv_data); i2c_set_adapdata(&drv_data->adapter, drv_data); -- cgit v1.2.3 From 541b6a7a69fadda82f313bd2176e7756db2b5b43 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sun, 27 Jan 2008 18:14:44 +0100 Subject: i2c-nforce2: The nForce2 can do block transactions My guess is that all the chips supported by this driver support block transactions and reset, but for now we play it safe and only list the ones for which this was actually tested. Signed-off-by: Jean Delvare Cc: Oleg Ryjkov --- drivers/i2c/busses/i2c-nforce2.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/i2c/busses') diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c index 1bf590c74166..3dac920e53ea 100644 --- a/drivers/i2c/busses/i2c-nforce2.c +++ b/drivers/i2c/busses/i2c-nforce2.c @@ -351,6 +351,7 @@ static int __devinit nforce2_probe(struct pci_dev *dev, const struct pci_device_ pci_set_drvdata(dev, smbuses); switch(dev->device) { + case PCI_DEVICE_ID_NVIDIA_NFORCE2_SMBUS: case PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SMBUS: case PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SMBUS: smbuses[0].blockops = 1; -- cgit v1.2.3 From ccf60d8571f0e606b5dacf213696b7a57fe2d890 Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Sun, 27 Jan 2008 18:14:44 +0100 Subject: i2c-pasemi: use i2c_add_numbered_adapter() Use numbered adapter registration to always have the same hardware bus show up at the same number. PWRficient 1682M has three buses, they are all on the same PCI device but different functions. So do the simple thing and register them based on function number. Future products, if having a different number of busses, are expected to have similar behaviour w.r.t. device/function layout. Signed-off-by: Olof Johansson Signed-off-by: Jean Delvare --- drivers/i2c/busses/i2c-pasemi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/i2c/busses') diff --git a/drivers/i2c/busses/i2c-pasemi.c b/drivers/i2c/busses/i2c-pasemi.c index ca18e0be4901..1603c81e39d4 100644 --- a/drivers/i2c/busses/i2c-pasemi.c +++ b/drivers/i2c/busses/i2c-pasemi.c @@ -368,6 +368,7 @@ static int __devinit pasemi_smb_probe(struct pci_dev *dev, smbus->adapter.class = I2C_CLASS_HWMON; smbus->adapter.algo = &smbus_algorithm; smbus->adapter.algo_data = smbus; + smbus->adapter.nr = PCI_FUNC(dev->devfn); /* set up the sysfs linkage to our parent device */ smbus->adapter.dev.parent = &dev->dev; @@ -375,7 +376,7 @@ static int __devinit pasemi_smb_probe(struct pci_dev *dev, reg_write(smbus, REG_CTL, (CTL_MTR | CTL_MRR | (CLK_100K_DIV & CTL_CLK_M))); - error = i2c_add_adapter(&smbus->adapter); + error = i2c_add_numbered_adapter(&smbus->adapter); if (error) goto out_release_region; -- cgit v1.2.3 From 217bcec4425cdc8fb90ce688eb4d5b5140713046 Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Sun, 27 Jan 2008 18:14:45 +0100 Subject: i2c-ibm_iic: Whitespace cleanup Signed-off-by: Stefan Roese Signed-off-by: Jean Delvare --- drivers/i2c/busses/i2c-ibm_iic.c | 190 +++++++++++++++++++-------------------- drivers/i2c/busses/i2c-ibm_iic.h | 8 +- 2 files changed, 99 insertions(+), 99 deletions(-) (limited to 'drivers/i2c/busses') diff --git a/drivers/i2c/busses/i2c-ibm_iic.c b/drivers/i2c/busses/i2c-ibm_iic.c index 9b43ff7270d0..d0cf39b8c1f1 100644 --- a/drivers/i2c/busses/i2c-ibm_iic.c +++ b/drivers/i2c/busses/i2c-ibm_iic.c @@ -6,7 +6,7 @@ * Copyright (c) 2003, 2004 Zultys Technologies. * Eugene Surovegin or * - * Based on original work by + * Based on original work by * Ian DaSilva * Armin Kuster * Matt Porter @@ -86,8 +86,8 @@ static void dump_iic_regs(const char* header, struct ibm_iic_private* dev) KERN_DEBUG " sts = 0x%02x, extsts = 0x%02x\n" KERN_DEBUG " clkdiv = 0x%02x, xfrcnt = 0x%02x\n" KERN_DEBUG " xtcntlss = 0x%02x, directcntl = 0x%02x\n", - in_8(&iic->cntl), in_8(&iic->mdcntl), in_8(&iic->sts), - in_8(&iic->extsts), in_8(&iic->clkdiv), in_8(&iic->xfrcnt), + in_8(&iic->cntl), in_8(&iic->mdcntl), in_8(&iic->sts), + in_8(&iic->extsts), in_8(&iic->clkdiv), in_8(&iic->xfrcnt), in_8(&iic->xtcntlss), in_8(&iic->directcntl)); } # define DUMP_REGS(h,dev) dump_iic_regs((h),(dev)) @@ -125,7 +125,7 @@ static inline void iic_interrupt_mode(struct ibm_iic_private* dev, int enable) { out_8(&dev->vaddr->intmsk, enable ? INTRMSK_EIMTC : 0); } - + /* * Initialize IIC interface. */ @@ -134,7 +134,7 @@ static void iic_dev_init(struct ibm_iic_private* dev) volatile struct iic_regs __iomem *iic = dev->vaddr; DBG("%d: init\n", dev->idx); - + /* Clear master address */ out_8(&iic->lmadr, 0); out_8(&iic->hmadr, 0); @@ -160,7 +160,7 @@ static void iic_dev_init(struct ibm_iic_private* dev) /* Clear control register */ out_8(&iic->cntl, 0); - + /* Enable interrupts if possible */ iic_interrupt_mode(dev, dev->irq >= 0); @@ -171,7 +171,7 @@ static void iic_dev_init(struct ibm_iic_private* dev) DUMP_REGS("iic_init", dev); } -/* +/* * Reset IIC interface */ static void iic_dev_reset(struct ibm_iic_private* dev) @@ -179,42 +179,42 @@ static void iic_dev_reset(struct ibm_iic_private* dev) volatile struct iic_regs __iomem *iic = dev->vaddr; int i; u8 dc; - + DBG("%d: soft reset\n", dev->idx); DUMP_REGS("reset", dev); - + /* Place chip in the reset state */ out_8(&iic->xtcntlss, XTCNTLSS_SRST); - + /* Check if bus is free */ - dc = in_8(&iic->directcntl); + dc = in_8(&iic->directcntl); if (!DIRCTNL_FREE(dc)){ DBG("%d: trying to regain bus control\n", dev->idx); - + /* Try to set bus free state */ - out_8(&iic->directcntl, DIRCNTL_SDAC | DIRCNTL_SCC); - + out_8(&iic->directcntl, DIRCNTL_SDAC | DIRCNTL_SCC); + /* Wait until we regain bus control */ for (i = 0; i < 100; ++i){ dc = in_8(&iic->directcntl); if (DIRCTNL_FREE(dc)) break; - + /* Toggle SCL line */ dc ^= DIRCNTL_SCC; out_8(&iic->directcntl, dc); udelay(10); dc ^= DIRCNTL_SCC; out_8(&iic->directcntl, dc); - + /* be nice */ cond_resched(); } } - + /* Remove reset */ out_8(&iic->xtcntlss, 0); - + /* Reinitialize interface */ iic_dev_init(dev); } @@ -324,14 +324,14 @@ static irqreturn_t iic_handler(int irq, void *dev_id) { struct ibm_iic_private* dev = (struct ibm_iic_private*)dev_id; volatile struct iic_regs __iomem *iic = dev->vaddr; - - DBG2("%d: irq handler, STS = 0x%02x, EXTSTS = 0x%02x\n", + + DBG2("%d: irq handler, STS = 0x%02x, EXTSTS = 0x%02x\n", dev->idx, in_8(&iic->sts), in_8(&iic->extsts)); - + /* Acknowledge IRQ and wakeup iic_wait_for_tc */ out_8(&iic->sts, STS_IRQA | STS_SCMP); wake_up_interruptible(&dev->wq); - + return IRQ_HANDLED; } @@ -341,19 +341,19 @@ static irqreturn_t iic_handler(int irq, void *dev_id) */ static int iic_xfer_result(struct ibm_iic_private* dev) { - volatile struct iic_regs __iomem *iic = dev->vaddr; - + volatile struct iic_regs __iomem *iic = dev->vaddr; + if (unlikely(in_8(&iic->sts) & STS_ERR)){ - DBG("%d: xfer error, EXTSTS = 0x%02x\n", dev->idx, + DBG("%d: xfer error, EXTSTS = 0x%02x\n", dev->idx, in_8(&iic->extsts)); - + /* Clear errors and possible pending IRQs */ - out_8(&iic->extsts, EXTSTS_IRQP | EXTSTS_IRQD | + out_8(&iic->extsts, EXTSTS_IRQP | EXTSTS_IRQD | EXTSTS_LA | EXTSTS_ICT | EXTSTS_XFRA); - + /* Flush master data buffer */ out_8(&iic->mdcntl, in_8(&iic->mdcntl) | MDCNTL_FMDB); - + /* Is bus free? * If error happened during combined xfer * IIC interface is usually stuck in some strange @@ -376,11 +376,11 @@ static void iic_abort_xfer(struct ibm_iic_private* dev) { volatile struct iic_regs __iomem *iic = dev->vaddr; unsigned long x; - + DBG("%d: iic_abort_xfer\n", dev->idx); - + out_8(&iic->cntl, CNTL_HMT); - + /* * Wait for the abort command to complete. * It's not worth to be optimized, just poll (timeout >= 1 tick) @@ -405,13 +405,13 @@ static void iic_abort_xfer(struct ibm_iic_private* dev) * Returns the number of transferred bytes or error (<0) */ static int iic_wait_for_tc(struct ibm_iic_private* dev){ - + volatile struct iic_regs __iomem *iic = dev->vaddr; int ret = 0; - + if (dev->irq >= 0){ /* Interrupt mode */ - ret = wait_event_interruptible_timeout(dev->wq, + ret = wait_event_interruptible_timeout(dev->wq, !(in_8(&iic->sts) & STS_PT), dev->adap.timeout * HZ); if (unlikely(ret < 0)) @@ -424,37 +424,37 @@ static int iic_wait_for_tc(struct ibm_iic_private* dev){ else { /* Polling mode */ unsigned long x = jiffies + dev->adap.timeout * HZ; - + while (in_8(&iic->sts) & STS_PT){ if (unlikely(time_after(jiffies, x))){ DBG("%d: poll timeout\n", dev->idx); ret = -ETIMEDOUT; break; } - + if (unlikely(signal_pending(current))){ DBG("%d: poll interrupted\n", dev->idx); ret = -ERESTARTSYS; break; } schedule(); - } + } } - + if (unlikely(ret < 0)) iic_abort_xfer(dev); else ret = iic_xfer_result(dev); - + DBG2("%d: iic_wait_for_tc -> %d\n", dev->idx, ret); - + return ret; } /* * Low level master transfer routine */ -static int iic_xfer_bytes(struct ibm_iic_private* dev, struct i2c_msg* pm, +static int iic_xfer_bytes(struct ibm_iic_private* dev, struct i2c_msg* pm, int combined_xfer) { volatile struct iic_regs __iomem *iic = dev->vaddr; @@ -465,48 +465,48 @@ static int iic_xfer_bytes(struct ibm_iic_private* dev, struct i2c_msg* pm, u8 cntl = (in_8(&iic->cntl) & CNTL_AMD) | CNTL_PT; if (pm->flags & I2C_M_RD) cntl |= CNTL_RW; - + loops = (len + 3) / 4; for (i = 0; i < loops; ++i, len -= 4){ int count = len > 4 ? 4 : len; u8 cmd = cntl | ((count - 1) << CNTL_TCT_SHIFT); - + if (!(cntl & CNTL_RW)) for (j = 0; j < count; ++j) out_8((void __iomem *)&iic->mdbuf, *buf++); - + if (i < loops - 1) cmd |= CNTL_CHT; else if (combined_xfer) cmd |= CNTL_RPST; - + DBG2("%d: xfer_bytes, %d, CNTL = 0x%02x\n", dev->idx, count, cmd); - + /* Start transfer */ out_8(&iic->cntl, cmd); - + /* Wait for completion */ ret = iic_wait_for_tc(dev); if (unlikely(ret < 0)) break; else if (unlikely(ret != count)){ - DBG("%d: xfer_bytes, requested %d, transfered %d\n", + DBG("%d: xfer_bytes, requested %d, transfered %d\n", dev->idx, count, ret); - + /* If it's not a last part of xfer, abort it */ if (combined_xfer || (i < loops - 1)) iic_abort_xfer(dev); - + ret = -EREMOTEIO; - break; + break; } - + if (cntl & CNTL_RW) for (j = 0; j < count; ++j) *buf++ = in_8((void __iomem *)&iic->mdbuf); } - + return ret > 0 ? 0 : ret; } @@ -517,10 +517,10 @@ static inline void iic_address(struct ibm_iic_private* dev, struct i2c_msg* msg) { volatile struct iic_regs __iomem *iic = dev->vaddr; u16 addr = msg->addr; - - DBG2("%d: iic_address, 0x%03x (%d-bit)\n", dev->idx, + + DBG2("%d: iic_address, 0x%03x (%d-bit)\n", dev->idx, addr, msg->flags & I2C_M_TEN ? 10 : 7); - + if (msg->flags & I2C_M_TEN){ out_8(&iic->cntl, CNTL_AMD); out_8(&iic->lmadr, addr); @@ -537,15 +537,15 @@ static inline int iic_invalid_address(const struct i2c_msg* p) return (p->addr > 0x3ff) || (!(p->flags & I2C_M_TEN) && (p->addr > 0x7f)); } -static inline int iic_address_neq(const struct i2c_msg* p1, +static inline int iic_address_neq(const struct i2c_msg* p1, const struct i2c_msg* p2) { - return (p1->addr != p2->addr) + return (p1->addr != p2->addr) || ((p1->flags & I2C_M_TEN) != (p2->flags & I2C_M_TEN)); -} +} /* - * Generic master transfer entrypoint. + * Generic master transfer entrypoint. * Returns the number of processed messages or error (<0) */ static int iic_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) @@ -553,20 +553,20 @@ static int iic_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) struct ibm_iic_private* dev = (struct ibm_iic_private*)(i2c_get_adapdata(adap)); volatile struct iic_regs __iomem *iic = dev->vaddr; int i, ret = 0; - + DBG2("%d: iic_xfer, %d msg(s)\n", dev->idx, num); - + if (!num) return 0; - + /* Check the sanity of the passed messages. * Uhh, generic i2c layer is more suitable place for such code... */ if (unlikely(iic_invalid_address(&msgs[0]))){ - DBG("%d: invalid address 0x%03x (%d-bit)\n", dev->idx, + DBG("%d: invalid address 0x%03x (%d-bit)\n", dev->idx, msgs[0].addr, msgs[0].flags & I2C_M_TEN ? 10 : 7); return -EINVAL; - } + } for (i = 0; i < num; ++i){ if (unlikely(msgs[i].len <= 0)){ if (num == 1 && !msgs[0].len){ @@ -576,7 +576,7 @@ static int iic_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) */ return iic_smbus_quick(dev, &msgs[0]); } - DBG("%d: invalid len %d in msg[%d]\n", dev->idx, + DBG("%d: invalid len %d in msg[%d]\n", dev->idx, msgs[i].len, i); return -EINVAL; } @@ -585,34 +585,34 @@ static int iic_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) return -EINVAL; } } - + /* Check bus state */ if (unlikely((in_8(&iic->extsts) & EXTSTS_BCS_MASK) != EXTSTS_BCS_FREE)){ DBG("%d: iic_xfer, bus is not free\n", dev->idx); - + /* Usually it means something serious has happend. * We *cannot* have unfinished previous transfer * so it doesn't make any sense to try to stop it. - * Probably we were not able to recover from the + * Probably we were not able to recover from the * previous error. * The only *reasonable* thing I can think of here * is soft reset. --ebs */ iic_dev_reset(dev); - + if ((in_8(&iic->extsts) & EXTSTS_BCS_MASK) != EXTSTS_BCS_FREE){ DBG("%d: iic_xfer, bus is still not free\n", dev->idx); return -EREMOTEIO; } - } + } else { /* Flush master data buffer (just in case) */ out_8(&iic->mdcntl, in_8(&iic->mdcntl) | MDCNTL_FMDB); } - + /* Load slave address */ iic_address(dev, &msgs[0]); - + /* Do real transfer */ for (i = 0; i < num && !ret; ++i) ret = iic_xfer_bytes(dev, &msgs[i], i < num - 1); @@ -648,7 +648,7 @@ static inline u8 iic_clckdiv(unsigned int opb) /* Convert to MHz */ opb /= 1000000; - + if (opb < 20 || opb > 150){ printk(KERN_CRIT "ibm-iic: invalid OPB clock frequency %u MHz\n", opb); @@ -666,7 +666,7 @@ static int __devinit iic_probe(struct ocp_device *ocp){ struct i2c_adapter* adap; struct ocp_func_iic_data* iic_data = ocp->def->additions; int ret; - + if (!iic_data) printk(KERN_WARNING"ibm-iic%d: missing additional data!\n", ocp->def->index); @@ -679,7 +679,7 @@ static int __devinit iic_probe(struct ocp_device *ocp){ dev->idx = ocp->def->index; ocp_set_drvdata(ocp, dev); - + if (!request_mem_region(ocp->def->paddr, sizeof(struct iic_regs), "ibm_iic")) { ret = -EBUSY; @@ -692,7 +692,7 @@ static int __devinit iic_probe(struct ocp_device *ocp){ ret = -ENXIO; goto fail2; } - + init_waitqueue_head(&dev->wq); dev->irq = iic_force_poll ? -1 : ocp->def->irq; @@ -702,29 +702,29 @@ static int __devinit iic_probe(struct ocp_device *ocp){ */ iic_interrupt_mode(dev, 0); if (request_irq(dev->irq, iic_handler, 0, "IBM IIC", dev)){ - printk(KERN_ERR "ibm-iic%d: request_irq %d failed\n", + printk(KERN_ERR "ibm-iic%d: request_irq %d failed\n", dev->idx, dev->irq); - /* Fallback to the polling mode */ + /* Fallback to the polling mode */ dev->irq = -1; } } - + if (dev->irq < 0) - printk(KERN_WARNING "ibm-iic%d: using polling mode\n", + printk(KERN_WARNING "ibm-iic%d: using polling mode\n", dev->idx); - + /* Board specific settings */ dev->fast_mode = iic_force_fast ? 1 : (iic_data ? iic_data->fast_mode : 0); - - /* clckdiv is the same for *all* IIC interfaces, + + /* clckdiv is the same for *all* IIC interfaces, * but I'd rather make a copy than introduce another global. --ebs */ dev->clckdiv = iic_clckdiv(ocp_sys_info.opb_bus_freq); DBG("%d: clckdiv = %d\n", dev->idx, dev->clckdiv); - + /* Initialize IIC interface */ iic_dev_init(dev); - + /* Register it with i2c layer */ adap = &dev->adap; adap->dev.parent = &ocp->dev; @@ -750,24 +750,24 @@ static int __devinit iic_probe(struct ocp_device *ocp){ dev->idx); goto fail; } - + printk(KERN_INFO "ibm-iic%d: using %s mode\n", dev->idx, dev->fast_mode ? "fast (400 kHz)" : "standard (100 kHz)"); return 0; -fail: +fail: if (dev->irq >= 0){ iic_interrupt_mode(dev, 0); free_irq(dev->irq, dev); - } + } iounmap(dev->vaddr); -fail2: +fail2: release_mem_region(ocp->def->paddr, sizeof(struct iic_regs)); fail1: ocp_set_drvdata(ocp, NULL); - kfree(dev); + kfree(dev); return ret; } @@ -783,13 +783,13 @@ static void __devexit iic_remove(struct ocp_device *ocp) dev->idx); /* That's *very* bad, just shutdown IRQ ... */ if (dev->irq >= 0){ - iic_interrupt_mode(dev, 0); + iic_interrupt_mode(dev, 0); free_irq(dev->irq, dev); dev->irq = -1; } } else { if (dev->irq >= 0){ - iic_interrupt_mode(dev, 0); + iic_interrupt_mode(dev, 0); free_irq(dev->irq, dev); } iounmap(dev->vaddr); @@ -798,7 +798,7 @@ static void __devexit iic_remove(struct ocp_device *ocp) } } -static struct ocp_device_id ibm_iic_ids[] __devinitdata = +static struct ocp_device_id ibm_iic_ids[] __devinitdata = { { .vendor = OCP_VENDOR_IBM, .function = OCP_FUNC_IIC }, { .vendor = OCP_VENDOR_INVALID } diff --git a/drivers/i2c/busses/i2c-ibm_iic.h b/drivers/i2c/busses/i2c-ibm_iic.h index 59d7b437f7ff..fdaa48292cb6 100644 --- a/drivers/i2c/busses/i2c-ibm_iic.h +++ b/drivers/i2c/busses/i2c-ibm_iic.h @@ -2,11 +2,11 @@ * drivers/i2c/busses/i2c-ibm_iic.h * * Support for the IIC peripheral on IBM PPC 4xx - * + * * Copyright (c) 2003 Zultys Technologies. * Eugene Surovegin or * - * Based on original work by + * Based on original work by * Ian DaSilva * Armin Kuster * Matt Porter @@ -22,7 +22,7 @@ #ifndef __I2C_IBM_IIC_H_ #define __I2C_IBM_IIC_H_ -#include +#include struct iic_regs { u16 mdbuf; @@ -58,7 +58,7 @@ struct ibm_iic_private { #define CNTL_TCT_MASK 0x30 #define CNTL_TCT_SHIFT 4 #define CNTL_RPST 0x08 -#define CNTL_CHT 0x04 +#define CNTL_CHT 0x04 #define CNTL_RW 0x02 #define CNTL_PT 0x01 -- cgit v1.2.3 From 569be443e3c1329fc6725988004f5d8a32fe3be5 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sun, 27 Jan 2008 18:14:45 +0100 Subject: i2c-stub: Use a single array for byte and word operations This mimics the behavior of actual SMBus chips better. Signed-off-by: Jean Delvare Cc: Mark M. Hoffman --- drivers/i2c/busses/i2c-stub.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'drivers/i2c/busses') diff --git a/drivers/i2c/busses/i2c-stub.c b/drivers/i2c/busses/i2c-stub.c index 84df29da1ddc..c2a9f8c94f5e 100644 --- a/drivers/i2c/busses/i2c-stub.c +++ b/drivers/i2c/busses/i2c-stub.c @@ -1,8 +1,8 @@ /* - i2c-stub.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring + i2c-stub.c - I2C/SMBus chip emulator Copyright (c) 2004 Mark M. Hoffman + Copyright (C) 2007 Jean Delvare 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 @@ -37,8 +37,8 @@ MODULE_PARM_DESC(chip_addr, struct stub_chip { u8 pointer; - u8 bytes[256]; - u16 words[256]; + u16 words[256]; /* Byte operations use the LSB as per SMBus + specification */ }; static struct stub_chip *stub_chips; @@ -75,7 +75,7 @@ static s32 stub_xfer(struct i2c_adapter * adap, u16 addr, unsigned short flags, "wrote 0x%02x.\n", addr, command); } else { - data->byte = chip->bytes[chip->pointer++]; + data->byte = chip->words[chip->pointer++] & 0xff; dev_dbg(&adap->dev, "smbus byte - addr 0x%02x, " "read 0x%02x.\n", addr, data->byte); @@ -86,12 +86,13 @@ static s32 stub_xfer(struct i2c_adapter * adap, u16 addr, unsigned short flags, case I2C_SMBUS_BYTE_DATA: if (read_write == I2C_SMBUS_WRITE) { - chip->bytes[command] = data->byte; + chip->words[command] &= 0xff00; + chip->words[command] |= data->byte; dev_dbg(&adap->dev, "smbus byte data - addr 0x%02x, " "wrote 0x%02x at 0x%02x.\n", addr, data->byte, command); } else { - data->byte = chip->bytes[command]; + data->byte = chip->words[command] & 0xff; dev_dbg(&adap->dev, "smbus byte data - addr 0x%02x, " "read 0x%02x at 0x%02x.\n", addr, data->byte, command); -- cgit v1.2.3 From 7e8b99251be8b6f992baa88e3a6ba3c4ae01660b Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Sun, 27 Jan 2008 18:14:46 +0100 Subject: i2c: some overdue driver removal This patch contains the overdue removal of three I2C drivers. [JD: In fact only i2c-ixp4xx can be removed at the moment, the other two platforms don't implement the generic GPIO layer yet.] Signed-off-by: Adrian Bunk Signed-off-by: Jean Delvare --- drivers/i2c/busses/Kconfig | 14 ---- drivers/i2c/busses/Makefile | 1 - drivers/i2c/busses/i2c-ixp4xx.c | 178 ---------------------------------------- 3 files changed, 193 deletions(-) delete mode 100644 drivers/i2c/busses/i2c-ixp4xx.c (limited to 'drivers/i2c/busses') diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index c466c6cfc2e5..2cef92a0bd0e 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -259,20 +259,6 @@ config I2C_IOP3XX This driver can also be built as a module. If so, the module will be called i2c-iop3xx. -config I2C_IXP4XX - tristate "IXP4xx GPIO-Based I2C Interface (DEPRECATED)" - depends on ARCH_IXP4XX - select I2C_ALGOBIT - help - Say Y here if you have an Intel IXP4xx(420,421,422,425) based - system and are using GPIO lines for an I2C bus. - - This support is also available as a module. If so, the module - will be called i2c-ixp4xx. - - This driver is deprecated and will be dropped soon. Use i2c-gpio - instead. - config I2C_IXP2000 tristate "IXP2000 GPIO-Based I2C Interface (DEPRECATED)" depends on ARCH_IXP2000 diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 81d43c27cf93..ea7068f1eb6b 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -20,7 +20,6 @@ obj-$(CONFIG_I2C_I810) += i2c-i810.o obj-$(CONFIG_I2C_IBM_IIC) += i2c-ibm_iic.o obj-$(CONFIG_I2C_IOP3XX) += i2c-iop3xx.o obj-$(CONFIG_I2C_IXP2000) += i2c-ixp2000.o -obj-$(CONFIG_I2C_IXP4XX) += i2c-ixp4xx.o obj-$(CONFIG_I2C_POWERMAC) += i2c-powermac.o obj-$(CONFIG_I2C_MPC) += i2c-mpc.o obj-$(CONFIG_I2C_MV64XXX) += i2c-mv64xxx.o diff --git a/drivers/i2c/busses/i2c-ixp4xx.c b/drivers/i2c/busses/i2c-ixp4xx.c deleted file mode 100644 index 069ed7f3b395..000000000000 --- a/drivers/i2c/busses/i2c-ixp4xx.c +++ /dev/null @@ -1,178 +0,0 @@ -/* - * drivers/i2c/busses/i2c-ixp4xx.c - * - * Intel's IXP4xx XScale NPU chipsets (IXP420, 421, 422, 425) do not have - * an on board I2C controller but provide 16 GPIO pins that are often - * used to create an I2C bus. This driver provides an i2c_adapter - * interface that plugs in under algo_bit and drives the GPIO pins - * as instructed by the alogorithm driver. - * - * Author: Deepak Saxena - * - * Copyright (c) 2003-2004 MontaVista Software Inc. - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - * - * NOTE: Since different platforms will use different GPIO pins for - * I2C, this driver uses an IXP4xx-specific platform_data - * pointer to pass the GPIO numbers to the driver. This - * allows us to support all the different IXP4xx platforms - * w/o having to put #ifdefs in this driver. - * - * See arch/arm/mach-ixp4xx/ixdp425.c for an example of building a - * device list and filling in the ixp4xx_i2c_pins data structure - * that is passed as the platform_data to this driver. - */ - -#include -#include -#include -#include -#include -#include - -#include /* Pick up IXP4xx-specific bits */ - -static inline int ixp4xx_scl_pin(void *data) -{ - return ((struct ixp4xx_i2c_pins*)data)->scl_pin; -} - -static inline int ixp4xx_sda_pin(void *data) -{ - return ((struct ixp4xx_i2c_pins*)data)->sda_pin; -} - -static void ixp4xx_bit_setscl(void *data, int val) -{ - gpio_line_set(ixp4xx_scl_pin(data), 0); - gpio_line_config(ixp4xx_scl_pin(data), - val ? IXP4XX_GPIO_IN : IXP4XX_GPIO_OUT ); -} - -static void ixp4xx_bit_setsda(void *data, int val) -{ - gpio_line_set(ixp4xx_sda_pin(data), 0); - gpio_line_config(ixp4xx_sda_pin(data), - val ? IXP4XX_GPIO_IN : IXP4XX_GPIO_OUT ); -} - -static int ixp4xx_bit_getscl(void *data) -{ - int scl; - - gpio_line_config(ixp4xx_scl_pin(data), IXP4XX_GPIO_IN ); - gpio_line_get(ixp4xx_scl_pin(data), &scl); - - return scl; -} - -static int ixp4xx_bit_getsda(void *data) -{ - int sda; - - gpio_line_config(ixp4xx_sda_pin(data), IXP4XX_GPIO_IN ); - gpio_line_get(ixp4xx_sda_pin(data), &sda); - - return sda; -} - -struct ixp4xx_i2c_data { - struct ixp4xx_i2c_pins *gpio_pins; - struct i2c_adapter adapter; - struct i2c_algo_bit_data algo_data; -}; - -static int ixp4xx_i2c_remove(struct platform_device *plat_dev) -{ - struct ixp4xx_i2c_data *drv_data = platform_get_drvdata(plat_dev); - - platform_set_drvdata(plat_dev, NULL); - - i2c_del_adapter(&drv_data->adapter); - - kfree(drv_data); - - return 0; -} - -static int ixp4xx_i2c_probe(struct platform_device *plat_dev) -{ - int err; - struct ixp4xx_i2c_pins *gpio = plat_dev->dev.platform_data; - struct ixp4xx_i2c_data *drv_data = - kzalloc(sizeof(struct ixp4xx_i2c_data), GFP_KERNEL); - - if(!drv_data) - return -ENOMEM; - - drv_data->gpio_pins = gpio; - - /* - * We could make a lot of these structures static, but - * certain platforms may have multiple GPIO-based I2C - * buses for various device domains, so we need per-device - * algo_data->data. - */ - drv_data->algo_data.data = gpio; - drv_data->algo_data.setsda = ixp4xx_bit_setsda; - drv_data->algo_data.setscl = ixp4xx_bit_setscl; - drv_data->algo_data.getsda = ixp4xx_bit_getsda; - drv_data->algo_data.getscl = ixp4xx_bit_getscl; - drv_data->algo_data.udelay = 10; - drv_data->algo_data.timeout = 100; - - drv_data->adapter.id = I2C_HW_B_IXP4XX; - drv_data->adapter.class = I2C_CLASS_HWMON; - strlcpy(drv_data->adapter.name, plat_dev->dev.driver->name, - sizeof(drv_data->adapter.name)); - drv_data->adapter.algo_data = &drv_data->algo_data; - - drv_data->adapter.dev.parent = &plat_dev->dev; - - gpio_line_config(gpio->scl_pin, IXP4XX_GPIO_IN); - gpio_line_config(gpio->sda_pin, IXP4XX_GPIO_IN); - gpio_line_set(gpio->scl_pin, 0); - gpio_line_set(gpio->sda_pin, 0); - - err = i2c_bit_add_bus(&drv_data->adapter); - if (err) { - printk(KERN_ERR "ERROR: Could not install %s\n", plat_dev->dev.bus_id); - - kfree(drv_data); - return err; - } - - platform_set_drvdata(plat_dev, drv_data); - - return 0; -} - -static struct platform_driver ixp4xx_i2c_driver = { - .probe = ixp4xx_i2c_probe, - .remove = ixp4xx_i2c_remove, - .driver = { - .name = "IXP4XX-I2C", - .owner = THIS_MODULE, - }, -}; - -static int __init ixp4xx_i2c_init(void) -{ - return platform_driver_register(&ixp4xx_i2c_driver); -} - -static void __exit ixp4xx_i2c_exit(void) -{ - platform_driver_unregister(&ixp4xx_i2c_driver); -} - -module_init(ixp4xx_i2c_init); -module_exit(ixp4xx_i2c_exit); - -MODULE_DESCRIPTION("GPIO-based I2C adapter for IXP4xx systems"); -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Deepak Saxena "); - -- cgit v1.2.3 From 59d70df025473931c500d6d60510798e4bfa3279 Mon Sep 17 00:00:00 2001 From: eric miao Date: Sun, 27 Jan 2008 18:14:46 +0100 Subject: i2c-pxa: Remove hardcoded #ifdef and use cpu_is_pxa27x remove #ifdef CONFIG_PXA27x .. #endif and use cpu_is_pxaXXXX() macros so that a single binary can support PXA25x/PXA27x/PXA3xx at run-time. Signed-off-by: eric miao Signed-off-by: Jean Delvare --- drivers/i2c/busses/i2c-pxa.c | 58 ++++++++++++++++++++++---------------------- 1 file changed, 29 insertions(+), 29 deletions(-) (limited to 'drivers/i2c/busses') diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c index 6426a61f8d4d..da3ecf5c591b 100644 --- a/drivers/i2c/busses/i2c-pxa.c +++ b/drivers/i2c/busses/i2c-pxa.c @@ -840,6 +840,32 @@ static const struct i2c_algorithm i2c_pxa_algorithm = { .functionality = i2c_pxa_functionality, }; +static void i2c_pxa_enable(struct platform_device *dev) +{ + if (cpu_is_pxa27x()) { + switch (dev->id) { + case 0: + pxa_gpio_mode(GPIO117_I2CSCL_MD); + pxa_gpio_mode(GPIO118_I2CSDA_MD); + break; + case 1: + local_irq_disable(); + PCFR |= PCFR_PI2CEN; + local_irq_enable(); + break; + } + } +} + +static void i2c_pxa_disable(struct platform_device *dev) +{ + if (cpu_is_pxa27x() && dev->id == 1) { + local_irq_disable(); + PCFR &= ~PCFR_PI2CEN; + local_irq_enable(); + } +} + #define res_len(r) ((r)->end - (r)->start + 1) static int i2c_pxa_probe(struct platform_device *dev) { @@ -899,25 +925,13 @@ static int i2c_pxa_probe(struct platform_device *dev) #endif clk_enable(i2c->clk); -#ifdef CONFIG_PXA27x - switch (dev->id) { - case 0: - pxa_gpio_mode(GPIO117_I2CSCL_MD); - pxa_gpio_mode(GPIO118_I2CSDA_MD); - break; - case 1: - local_irq_disable(); - PCFR |= PCFR_PI2CEN; - local_irq_enable(); - } -#endif + i2c_pxa_enable(dev); ret = request_irq(irq, i2c_pxa_handler, IRQF_DISABLED, i2c->adap.name, i2c); if (ret) goto ereqirq; - i2c_pxa_reset(i2c); i2c->adap.algo_data = i2c; @@ -955,14 +969,7 @@ eadapt: free_irq(irq, i2c); ereqirq: clk_disable(i2c->clk); - -#ifdef CONFIG_PXA27x - if (dev->id == 1) { - local_irq_disable(); - PCFR &= ~PCFR_PI2CEN; - local_irq_enable(); - } -#endif + i2c_pxa_disable(dev); eremap: clk_put(i2c->clk); eclk: @@ -983,14 +990,7 @@ static int i2c_pxa_remove(struct platform_device *dev) clk_disable(i2c->clk); clk_put(i2c->clk); - -#ifdef CONFIG_PXA27x - if (dev->id == 1) { - local_irq_disable(); - PCFR &= ~PCFR_PI2CEN; - local_irq_enable(); - } -#endif + i2c_pxa_disable(dev); release_mem_region(i2c->iobase, i2c->iosize); kfree(i2c); -- cgit v1.2.3 From 2caeac810423556a5ee787d5cb7aa902fda13bb4 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sun, 27 Jan 2008 18:14:47 +0100 Subject: i2c: Don't uselessly set i2c_adapter.retries I2C adapter drivers are supposed to handle retries on nack by themselves if they do, so there's no point in setting .retries if they don't. As this retry mechanism is going away (at least in its current form), clean this up now so that we don't get build failures later. Signed-off-by: Jean Delvare --- drivers/i2c/busses/i2c-davinci.c | 1 - drivers/i2c/busses/i2c-ibm_iic.c | 1 - drivers/i2c/busses/i2c-iop3xx.c | 1 - drivers/i2c/busses/i2c-mpc.c | 1 - drivers/i2c/busses/i2c-omap.c | 2 -- 5 files changed, 6 deletions(-) (limited to 'drivers/i2c/busses') diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c index 67679882ebef..cce5a614758d 100644 --- a/drivers/i2c/busses/i2c-davinci.c +++ b/drivers/i2c/busses/i2c-davinci.c @@ -510,7 +510,6 @@ static int davinci_i2c_probe(struct platform_device *pdev) /* FIXME */ adap->timeout = 1; - adap->retries = 1; adap->nr = pdev->id; r = i2c_add_numbered_adapter(adap); diff --git a/drivers/i2c/busses/i2c-ibm_iic.c b/drivers/i2c/busses/i2c-ibm_iic.c index d0cf39b8c1f1..7c7eb0cfeceb 100644 --- a/drivers/i2c/busses/i2c-ibm_iic.c +++ b/drivers/i2c/busses/i2c-ibm_iic.c @@ -736,7 +736,6 @@ static int __devinit iic_probe(struct ocp_device *ocp){ adap->client_register = NULL; adap->client_unregister = NULL; adap->timeout = 1; - adap->retries = 1; /* * If "dev->idx" is negative we consider it as zero. diff --git a/drivers/i2c/busses/i2c-iop3xx.c b/drivers/i2c/busses/i2c-iop3xx.c index c70146e4c2c0..ab41400c883e 100644 --- a/drivers/i2c/busses/i2c-iop3xx.c +++ b/drivers/i2c/busses/i2c-iop3xx.c @@ -490,7 +490,6 @@ iop3xx_i2c_probe(struct platform_device *pdev) * Default values...should these come in from board code? */ new_adapter->timeout = 100; - new_adapter->retries = 3; new_adapter->algo = &iop3xx_i2c_algo; init_waitqueue_head(&adapter_data->waitq); diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c index d8de4ac88b7d..81335b76c425 100644 --- a/drivers/i2c/busses/i2c-mpc.c +++ b/drivers/i2c/busses/i2c-mpc.c @@ -309,7 +309,6 @@ static struct i2c_adapter mpc_ops = { .algo = &mpc_algo, .class = I2C_CLASS_HWMON, .timeout = 1, - .retries = 1 }; static int fsl_i2c_probe(struct platform_device *pdev) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index f2552b19ea60..da6639707ea3 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -362,8 +362,6 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) omap_i2c_enable_clocks(dev); - /* REVISIT: initialize and use adap->retries. This is an optional - * feature */ if ((r = omap_i2c_wait_for_bb(dev)) < 0) goto out; -- cgit v1.2.3 From 0f79b72e45da68bf542a63a08f9c924b91b507e7 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sun, 27 Jan 2008 18:14:47 +0100 Subject: i2c: Deprecate drivers for I2C buses on video adapters The framebuffer drivers for these pieces of hardware include support for the DDC/I2C buses, so there is no need for separate drivers. Signed-off-by: Jean Delvare --- drivers/i2c/busses/Kconfig | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) (limited to 'drivers/i2c/busses') diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 2cef92a0bd0e..a38ba04fe36e 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -182,7 +182,8 @@ config I2C_I801 will be called i2c-i801. config I2C_I810 - tristate "Intel 810/815" + tristate "Intel 810/815 (DEPRECATED)" + default n depends on PCI select I2C_ALGOBIT help @@ -195,6 +196,8 @@ config I2C_I810 i815 i845G + This driver is deprecated in favor of the i810fb and intelfb drivers. + This driver can also be built as a module. If so, the module will be called i2c-i810. @@ -382,7 +385,8 @@ config I2C_PASEMI Supports the PA Semi PWRficient on-chip SMBus interfaces. config I2C_PROSAVAGE - tristate "S3/VIA (Pro)Savage" + tristate "S3/VIA (Pro)Savage (DEPRECATED)" + default n depends on PCI select I2C_ALGOBIT help @@ -393,6 +397,8 @@ config I2C_PROSAVAGE S3/VIA KM266/VT8375 aka ProSavage8 S3/VIA KM133/VT8365 aka Savage4 + This driver is deprecated in favor of the savagefb driver. + This support is also available as a module. If so, the module will be called i2c-prosavage. @@ -404,13 +410,16 @@ config I2C_S3C2410 Samsung S3C2410 based System-on-Chip devices. config I2C_SAVAGE4 - tristate "S3 Savage 4" - depends on PCI && EXPERIMENTAL + tristate "S3 Savage 4 (DEPRECATED)" + default n + depends on PCI select I2C_ALGOBIT help If you say yes to this option, support will be included for the S3 Savage 4 I2C interface. + This driver is deprecated in favor of the savagefb driver. + This driver can also be built as a module. If so, the module will be called i2c-savage4. -- cgit v1.2.3 From ae7b0497b8280ad5ecfe7bd045c5106f35950c8a Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sun, 27 Jan 2008 18:14:49 +0100 Subject: i2c-i801: Document which chip support what feature Provide a clearer documentation of which additional features each ICH chip support, and which of these the driver supports. Signed-off-by: Jean Delvare --- drivers/i2c/busses/i2c-i801.c | 57 +++++++++++++++++++++++++------------------ 1 file changed, 33 insertions(+), 24 deletions(-) (limited to 'drivers/i2c/busses') diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index ac27e5f84ebe..8f16a47bcaf9 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -21,25 +21,34 @@ */ /* - SUPPORTED DEVICES PCI ID - 82801AA 2413 - 82801AB 2423 - 82801BA 2443 - 82801CA/CAM 2483 - 82801DB 24C3 (HW PEC supported) - 82801EB 24D3 (HW PEC supported) - 6300ESB 25A4 - ICH6 266A - ICH7 27DA - ESB2 269B - ICH8 283E - ICH9 2930 - Tolapai 5032 - This driver supports several versions of Intel's I/O Controller Hubs (ICH). - For SMBus support, they are similar to the PIIX4 and are part - of Intel's '810' and other chipsets. - See the file Documentation/i2c/busses/i2c-i801 for details. - I2C Block Read and Process Call are not supported. + Supports the following Intel I/O Controller Hubs (ICH): + + I/O Block I2C + region SMBus Block proc. block + Chip name PCI ID size PEC buffer call read + ---------------------------------------------------------------------- + 82801AA (ICH) 0x2413 16 no no no no + 82801AB (ICH0) 0x2423 16 no no no no + 82801BA (ICH2) 0x2443 16 no no no no + 82801CA (ICH3) 0x2483 32 soft no no no + 82801DB (ICH4) 0x24c3 32 hard yes no no + 82801E (ICH5) 0x24d3 32 hard yes yes yes + 6300ESB 0x25a4 32 hard yes yes yes + 82801F (ICH6) 0x266a 32 hard yes yes yes + 6310ESB/6320ESB 0x269b 32 hard yes yes yes + 82801G (ICH7) 0x27da 32 hard yes yes yes + 82801H (ICH8) 0x283e 32 hard yes yes yes + 82801I (ICH9) 0x2930 32 hard yes yes yes + Tolapai 0x5032 32 hard yes ? ? + + Features supported by this driver: + Software PEC no + Hardware PEC yes + Block buffer yes + Block process call transaction no + I2C block read transaction no + + See the file Documentation/i2c/busses/i2c-i801 for details. */ /* Note: we assume there can only be one I801, with one SMBus interface */ @@ -62,9 +71,9 @@ #define SMBHSTDAT0 (5 + i801_smba) #define SMBHSTDAT1 (6 + i801_smba) #define SMBBLKDAT (7 + i801_smba) -#define SMBPEC (8 + i801_smba) /* ICH4 only */ -#define SMBAUXSTS (12 + i801_smba) /* ICH4 only */ -#define SMBAUXCTL (13 + i801_smba) /* ICH4 only */ +#define SMBPEC (8 + i801_smba) /* ICH3 and later */ +#define SMBAUXSTS (12 + i801_smba) /* ICH4 and later */ +#define SMBAUXCTL (13 + i801_smba) /* ICH4 and later */ /* PCI Address Constants */ #define SMBBAR 4 @@ -91,13 +100,13 @@ #define I801_BYTE 0x04 #define I801_BYTE_DATA 0x08 #define I801_WORD_DATA 0x0C -#define I801_PROC_CALL 0x10 /* later chips only, unimplemented */ +#define I801_PROC_CALL 0x10 /* unimplemented */ #define I801_BLOCK_DATA 0x14 #define I801_I2C_BLOCK_DATA 0x18 /* unimplemented */ #define I801_BLOCK_LAST 0x34 #define I801_I2C_BLOCK_LAST 0x38 /* unimplemented */ #define I801_START 0x40 -#define I801_PEC_EN 0x80 /* ICH4 only */ +#define I801_PEC_EN 0x80 /* ICH3 and later */ /* I801 Hosts Status register bits */ #define SMBHSTSTS_BYTE_DONE 0x80 -- cgit v1.2.3 From 369f6f4aec5315012ff5d951e0179f860c35c181 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sun, 27 Jan 2008 18:14:50 +0100 Subject: i2c-i801: More explicit names for chip features Use separate flags with explicit names to describe the features of the ICH chip. Signed-off-by: Jean Delvare --- drivers/i2c/busses/i2c-i801.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) (limited to 'drivers/i2c/busses') diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 8f16a47bcaf9..c31699d8df3a 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -122,7 +122,12 @@ static unsigned long i801_smba; static unsigned char i801_original_hstcfg; static struct pci_driver i801_driver; static struct pci_dev *I801_dev; -static int isich4; + +#define FEATURE_SMBUS_PEC (1 << 0) +#define FEATURE_BLOCK_BUFFER (1 << 1) +#define FEATURE_BLOCK_PROC (1 << 2) +#define FEATURE_I2C_BLOCK_READ (1 << 3) +static unsigned int i801_features; static int i801_transaction(int xact) { @@ -409,7 +414,8 @@ static int i801_block_transaction(union i2c_smbus_data *data, char read_write, data->block[0] = 32; /* max for reads */ } - if (isich4 && i801_set_block_buffer_mode() == 0 ) + if ((i801_features & FEATURE_BLOCK_BUFFER) + && i801_set_block_buffer_mode() == 0) result = i801_block_transaction_by_block(data, read_write, hwpec); else @@ -435,7 +441,7 @@ static s32 i801_access(struct i2c_adapter * adap, u16 addr, int block = 0; int ret, xact = 0; - hwpec = isich4 && (flags & I2C_CLIENT_PEC) + hwpec = (i801_features & FEATURE_SMBUS_PEC) && (flags & I2C_CLIENT_PEC) && size != I2C_SMBUS_QUICK && size != I2C_SMBUS_I2C_BLOCK_DATA; @@ -523,9 +529,9 @@ static s32 i801_access(struct i2c_adapter * adap, u16 addr, static u32 i801_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 | I2C_FUNC_SMBUS_WRITE_I2C_BLOCK - | (isich4 ? I2C_FUNC_SMBUS_PEC : 0); + I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | + I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_WRITE_I2C_BLOCK | + ((i801_features & FEATURE_SMBUS_PEC) ? I2C_FUNC_SMBUS_PEC : 0); } static const struct i2c_algorithm smbus_algorithm = { @@ -565,6 +571,7 @@ static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id int err; I801_dev = dev; + i801_features = 0; switch (dev->device) { case PCI_DEVICE_ID_INTEL_82801DB_3: case PCI_DEVICE_ID_INTEL_82801EB_3: @@ -575,10 +582,9 @@ static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id case PCI_DEVICE_ID_INTEL_ICH8_5: case PCI_DEVICE_ID_INTEL_ICH9_6: case PCI_DEVICE_ID_INTEL_TOLAPAI_1: - isich4 = 1; + i801_features |= FEATURE_SMBUS_PEC; + i801_features |= FEATURE_BLOCK_BUFFER; break; - default: - isich4 = 0; } err = pci_enable_device(dev); -- cgit v1.2.3 From a0921b6c07dfbb59ac2d497e96438adaf4940f16 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sun, 27 Jan 2008 18:14:50 +0100 Subject: i2c-i801: Clear special mode bits as needed Clear special mode bits (PEC, block buffer) at driver load time, you never know in which state the device was left by its last user. Also make sure that we reset the block buffer mode at the end of every transaction, not only when PEC was used. Signed-off-by: Jean Delvare --- drivers/i2c/busses/i2c-i801.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/i2c/busses') diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index c31699d8df3a..0b1b1ae5e228 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -502,7 +502,7 @@ static s32 i801_access(struct i2c_adapter * adap, u16 addr, /* Some BIOSes don't like it when PEC is enabled at reboot or resume time, so we forcibly disable it after every transaction. Turn off E32B for the same reason. */ - if (hwpec) + if (hwpec || block) outb_p(inb_p(SMBAUXCTL) & ~(SMBAUXCTL_CRC | SMBAUXCTL_E32B), SMBAUXCTL); @@ -625,6 +625,11 @@ static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id else dev_dbg(&dev->dev, "SMBus using PCI Interrupt\n"); + /* Clear special mode bits */ + if (i801_features & (FEATURE_SMBUS_PEC | FEATURE_BLOCK_BUFFER)) + outb_p(inb_p(SMBAUXCTL) & ~(SMBAUXCTL_CRC | SMBAUXCTL_E32B), + SMBAUXCTL); + /* set up the sysfs linkage to our parent device */ i801_adapter.dev.parent = &dev->dev; -- cgit v1.2.3 From 6342064cad7a28d10504128d028bc4ba379d489d Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sun, 27 Jan 2008 18:14:50 +0100 Subject: i2c-i801: Implement I2C block read support I2C block read is supported since the ICH5. I couldn't get it to work using the block buffer, so it's using the old-style byte-by-byte mode for now. Note: I'm also updating the driver author... The i2c-i801 driver was really written by Mark Studebaker, even though he based his work on the i2c-piix4 driver which was written by Philip Edelbrock. Signed-off-by: Jean Delvare --- drivers/i2c/busses/i2c-i801.c | 79 +++++++++++++++++++++++++++++-------------- 1 file changed, 54 insertions(+), 25 deletions(-) (limited to 'drivers/i2c/busses') diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 0b1b1ae5e228..aa9157913b9a 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -4,6 +4,7 @@ Copyright (c) 1998 - 2002 Frodo Looijaard , Philip Edelbrock , and Mark D. Studebaker + Copyright (C) 2007 Jean Delvare 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 @@ -46,7 +47,7 @@ Hardware PEC yes Block buffer yes Block process call transaction no - I2C block read transaction no + I2C block read transaction yes (doesn't use the block buffer) See the file Documentation/i2c/busses/i2c-i801 for details. */ @@ -102,9 +103,9 @@ #define I801_WORD_DATA 0x0C #define I801_PROC_CALL 0x10 /* unimplemented */ #define I801_BLOCK_DATA 0x14 -#define I801_I2C_BLOCK_DATA 0x18 /* unimplemented */ +#define I801_I2C_BLOCK_DATA 0x18 /* ICH5 and later */ #define I801_BLOCK_LAST 0x34 -#define I801_I2C_BLOCK_LAST 0x38 /* unimplemented */ +#define I801_I2C_BLOCK_LAST 0x38 /* ICH5 and later */ #define I801_START 0x40 #define I801_PEC_EN 0x80 /* ICH3 and later */ @@ -256,7 +257,8 @@ static int i801_block_transaction_by_block(union i2c_smbus_data *data, } static int i801_block_transaction_byte_by_byte(union i2c_smbus_data *data, - char read_write, int hwpec) + char read_write, int command, + int hwpec) { int i, len; int smbcmd; @@ -273,16 +275,24 @@ static int i801_block_transaction_byte_by_byte(union i2c_smbus_data *data, } for (i = 1; i <= len; i++) { - if (i == len && read_write == I2C_SMBUS_READ) - smbcmd = I801_BLOCK_LAST; - else - smbcmd = I801_BLOCK_DATA; + if (i == len && read_write == I2C_SMBUS_READ) { + if (command == I2C_SMBUS_I2C_BLOCK_DATA) + smbcmd = I801_I2C_BLOCK_LAST; + else + smbcmd = I801_BLOCK_LAST; + } else { + if (command == I2C_SMBUS_I2C_BLOCK_DATA + && read_write == I2C_SMBUS_READ) + smbcmd = I801_I2C_BLOCK_DATA; + else + smbcmd = I801_BLOCK_DATA; + } outb_p(smbcmd | ENABLE_INT9, SMBHSTCNT); dev_dbg(&I801_dev->dev, "Block (pre %d): CNT=%02x, CMD=%02x, " - "ADD=%02x, DAT0=%02x, BLKDAT=%02x\n", i, + "ADD=%02x, DAT0=%02x, DAT1=%02x, BLKDAT=%02x\n", i, inb_p(SMBHSTCNT), inb_p(SMBHSTCMD), inb_p(SMBHSTADD), - inb_p(SMBHSTDAT0), inb_p(SMBBLKDAT)); + inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1), inb_p(SMBBLKDAT)); /* Make sure the SMBus host is ready to start transmitting */ temp = inb_p(SMBHSTSTS); @@ -346,7 +356,8 @@ static int i801_block_transaction_byte_by_byte(union i2c_smbus_data *data, dev_dbg(&I801_dev->dev, "Error: no response!\n"); } - if (i == 1 && read_write == I2C_SMBUS_READ) { + if (i == 1 && read_write == I2C_SMBUS_READ + && command != I2C_SMBUS_I2C_BLOCK_DATA) { len = inb_p(SMBHSTDAT0); if (len < 1 || len > I2C_SMBUS_BLOCK_MAX) return -1; @@ -367,9 +378,9 @@ static int i801_block_transaction_byte_by_byte(union i2c_smbus_data *data, temp); } dev_dbg(&I801_dev->dev, "Block (post %d): CNT=%02x, CMD=%02x, " - "ADD=%02x, DAT0=%02x, BLKDAT=%02x\n", i, + "ADD=%02x, DAT0=%02x, DAT1=%02x, BLKDAT=%02x\n", i, inb_p(SMBHSTCNT), inb_p(SMBHSTCMD), inb_p(SMBHSTADD), - inb_p(SMBHSTDAT0), inb_p(SMBBLKDAT)); + inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1), inb_p(SMBBLKDAT)); if (result < 0) return result; @@ -398,34 +409,38 @@ static int i801_block_transaction(union i2c_smbus_data *data, char read_write, pci_read_config_byte(I801_dev, SMBHSTCFG, &hostc); pci_write_config_byte(I801_dev, SMBHSTCFG, hostc | SMBHSTCFG_I2C_EN); - } else { + } else if (!(i801_features & FEATURE_I2C_BLOCK_READ)) { dev_err(&I801_dev->dev, - "I2C_SMBUS_I2C_BLOCK_READ not DB!\n"); + "I2C block read is unsupported!\n"); return -1; } } - if (read_write == I2C_SMBUS_WRITE) { + if (read_write == I2C_SMBUS_WRITE + || command == I2C_SMBUS_I2C_BLOCK_DATA) { if (data->block[0] < 1) data->block[0] = 1; if (data->block[0] > I2C_SMBUS_BLOCK_MAX) data->block[0] = I2C_SMBUS_BLOCK_MAX; } else { - data->block[0] = 32; /* max for reads */ + data->block[0] = 32; /* max for SMBus block reads */ } if ((i801_features & FEATURE_BLOCK_BUFFER) + && !(command == I2C_SMBUS_I2C_BLOCK_DATA + && read_write == I2C_SMBUS_READ) && i801_set_block_buffer_mode() == 0) result = i801_block_transaction_by_block(data, read_write, hwpec); else result = i801_block_transaction_byte_by_byte(data, read_write, - hwpec); + command, hwpec); if (result == 0 && hwpec) i801_wait_hwpec(); - if (command == I2C_SMBUS_I2C_BLOCK_DATA) { + if (command == I2C_SMBUS_I2C_BLOCK_DATA + && read_write == I2C_SMBUS_WRITE) { /* restore saved configuration register value */ pci_write_config_byte(I801_dev, SMBHSTCFG, hostc); } @@ -477,12 +492,23 @@ static s32 i801_access(struct i2c_adapter * adap, u16 addr, xact = I801_WORD_DATA; break; case I2C_SMBUS_BLOCK_DATA: - case I2C_SMBUS_I2C_BLOCK_DATA: outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), SMBHSTADD); outb_p(command, SMBHSTCMD); block = 1; break; + case I2C_SMBUS_I2C_BLOCK_DATA: + /* NB: page 240 of ICH5 datasheet shows that the R/#W + * bit should be cleared here, even when reading */ + outb_p((addr & 0x7f) << 1, SMBHSTADD); + if (read_write == I2C_SMBUS_READ) { + /* NB: page 240 of ICH5 datasheet also shows + * that DATA1 is the cmd field when reading */ + outb_p(command, SMBHSTDAT1); + } else + outb_p(command, SMBHSTCMD); + block = 1; + break; case I2C_SMBUS_PROC_CALL: default: dev_err(&I801_dev->dev, "Unsupported transaction %d\n", size); @@ -531,7 +557,9 @@ static u32 i801_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 | I2C_FUNC_SMBUS_WRITE_I2C_BLOCK | - ((i801_features & FEATURE_SMBUS_PEC) ? I2C_FUNC_SMBUS_PEC : 0); + ((i801_features & FEATURE_SMBUS_PEC) ? I2C_FUNC_SMBUS_PEC : 0) | + ((i801_features & FEATURE_I2C_BLOCK_READ) ? + I2C_FUNC_SMBUS_READ_I2C_BLOCK : 0); } static const struct i2c_algorithm smbus_algorithm = { @@ -573,7 +601,6 @@ static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id I801_dev = dev; i801_features = 0; switch (dev->device) { - case PCI_DEVICE_ID_INTEL_82801DB_3: case PCI_DEVICE_ID_INTEL_82801EB_3: case PCI_DEVICE_ID_INTEL_ESB_4: case PCI_DEVICE_ID_INTEL_ICH6_16: @@ -581,6 +608,9 @@ static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id case PCI_DEVICE_ID_INTEL_ESB2_17: case PCI_DEVICE_ID_INTEL_ICH8_5: case PCI_DEVICE_ID_INTEL_ICH9_6: + i801_features |= FEATURE_I2C_BLOCK_READ; + /* fall through */ + case PCI_DEVICE_ID_INTEL_82801DB_3: case PCI_DEVICE_ID_INTEL_TOLAPAI_1: i801_features |= FEATURE_SMBUS_PEC; i801_features |= FEATURE_BLOCK_BUFFER; @@ -698,9 +728,8 @@ static void __exit i2c_i801_exit(void) pci_unregister_driver(&i801_driver); } -MODULE_AUTHOR ("Frodo Looijaard , " - "Philip Edelbrock , " - "and Mark D. Studebaker "); +MODULE_AUTHOR("Mark D. Studebaker , " + "Jean Delvare "); MODULE_DESCRIPTION("I801 SMBus driver"); MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 5271071b20dee56c01b6b9d8e275611403d3d383 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sun, 27 Jan 2008 18:14:50 +0100 Subject: i2c-sibyte: Remove the bus scan module parameter The implementation is unsafe, and anyway one can achieve the same from userspace using i2c-dev + i2cdetect. Also tag i2c_sibyte_add_bus __init. Signed-off-by: Jean Delvare Cc: Ralf Baechle --- drivers/i2c/busses/i2c-sibyte.c | 29 +---------------------------- 1 file changed, 1 insertion(+), 28 deletions(-) (limited to 'drivers/i2c/busses') diff --git a/drivers/i2c/busses/i2c-sibyte.c b/drivers/i2c/busses/i2c-sibyte.c index 503a134ec803..8fbbdb4c2f35 100644 --- a/drivers/i2c/busses/i2c-sibyte.c +++ b/drivers/i2c/busses/i2c-sibyte.c @@ -36,14 +36,6 @@ struct i2c_algo_sibyte_data { /* ----- global defines ----------------------------------------------- */ #define SMB_CSR(a,r) ((long)(a->reg_base + r)) -/* ----- global variables --------------------------------------------- */ - -/* module parameters: - */ -static int bit_scan; /* have a look at what's hanging 'round */ -module_param(bit_scan, int, 0); -MODULE_PARM_DESC(bit_scan, "Scan for active chips on the bus"); - static int smbus_xfer(struct i2c_adapter *i2c_adap, u16 addr, unsigned short flags, char read_write, @@ -140,9 +132,8 @@ static const struct i2c_algorithm i2c_sibyte_algo = { /* * registering functions to load algorithms at runtime */ -int i2c_sibyte_add_bus(struct i2c_adapter *i2c_adap, int speed) +int __init i2c_sibyte_add_bus(struct i2c_adapter *i2c_adap, int speed) { - int i; struct i2c_algo_sibyte_data *adap = i2c_adap->algo_data; /* register new adapter to i2c module... */ @@ -152,24 +143,6 @@ int i2c_sibyte_add_bus(struct i2c_adapter *i2c_adap, int speed) csr_out32(speed, SMB_CSR(adap,R_SMB_FREQ)); csr_out32(0, SMB_CSR(adap,R_SMB_CONTROL)); - /* scan bus */ - if (bit_scan) { - union i2c_smbus_data data; - int rc; - printk(KERN_INFO " i2c-algo-sibyte.o: scanning bus %s.\n", - i2c_adap->name); - for (i = 0x00; i < 0x7f; i++) { - /* XXXKW is this a realistic probe? */ - rc = smbus_xfer(i2c_adap, i, 0, I2C_SMBUS_READ, 0, - I2C_SMBUS_BYTE_DATA, &data); - if (!rc) { - printk("(%02x)",i); - } else - printk("."); - } - printk("\n"); - } - return i2c_add_adapter(i2c_adap); } -- cgit v1.2.3 From b7a3670131c7662415fa799700fc0bdfe90a54b6 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Sun, 27 Jan 2008 18:14:50 +0100 Subject: i2c-pxa: Add polling transfer Add polling I2C transfer implementation for PXA I2C. This is needed for cases where I2C transactions have to occur at times interrups are disabled. Signed-off-by: Mike Rapoport Acked-by: eric miao Signed-off-by: Jean Delvare --- drivers/i2c/busses/i2c-pxa.c | 133 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 121 insertions(+), 12 deletions(-) (limited to 'drivers/i2c/busses') diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c index da3ecf5c591b..2598d29fd7a4 100644 --- a/drivers/i2c/busses/i2c-pxa.c +++ b/drivers/i2c/busses/i2c-pxa.c @@ -65,6 +65,7 @@ struct pxa_i2c { unsigned long iosize; int irq; + int use_pio; }; #define _IBMR(i2c) ((i2c)->reg_base + 0) @@ -163,6 +164,7 @@ static void i2c_pxa_show_state(struct pxa_i2c *i2c, int lno, const char *fname) #define eedbg(lvl, x...) do { if ((lvl) < 1) { printk(KERN_DEBUG "" x); } } while(0) static void i2c_pxa_master_complete(struct pxa_i2c *i2c, int ret); +static irqreturn_t i2c_pxa_handler(int this_irq, void *dev_id); static void i2c_pxa_scream_blue_murder(struct pxa_i2c *i2c, const char *why) { @@ -554,6 +556,71 @@ static inline void i2c_pxa_stop_message(struct pxa_i2c *i2c) writel(icr, _ICR(i2c)); } +static int i2c_pxa_pio_set_master(struct pxa_i2c *i2c) +{ + /* make timeout the same as for interrupt based functions */ + long timeout = 2 * DEF_TIMEOUT; + + /* + * Wait for the bus to become free. + */ + while (timeout-- && readl(_ISR(i2c)) & (ISR_IBB | ISR_UB)) { + udelay(1000); + show_state(i2c); + } + + if (timeout <= 0) { + show_state(i2c); + dev_err(&i2c->adap.dev, + "i2c_pxa: timeout waiting for bus free\n"); + return I2C_RETRY; + } + + /* + * Set master mode. + */ + writel(readl(_ICR(i2c)) | ICR_SCLE, _ICR(i2c)); + + return 0; +} + +static int i2c_pxa_do_pio_xfer(struct pxa_i2c *i2c, + struct i2c_msg *msg, int num) +{ + unsigned long timeout = 500000; /* 5 seconds */ + int ret = 0; + + ret = i2c_pxa_pio_set_master(i2c); + if (ret) + goto out; + + i2c->msg = msg; + i2c->msg_num = num; + i2c->msg_idx = 0; + i2c->msg_ptr = 0; + i2c->irqlogidx = 0; + + i2c_pxa_start_message(i2c); + + while (timeout-- && i2c->msg_num > 0) { + i2c_pxa_handler(0, i2c); + udelay(10); + } + + i2c_pxa_stop_message(i2c); + + /* + * We place the return code in i2c->msg_idx. + */ + ret = i2c->msg_idx; + +out: + if (timeout == 0) + i2c_pxa_scream_blue_murder(i2c, "timeout"); + + return ret; +} + /* * We are protected by the adapter bus mutex. */ @@ -610,6 +677,35 @@ static int i2c_pxa_do_xfer(struct pxa_i2c *i2c, struct i2c_msg *msg, int num) return ret; } +static int i2c_pxa_pio_xfer(struct i2c_adapter *adap, + struct i2c_msg msgs[], int num) +{ + struct pxa_i2c *i2c = adap->algo_data; + int ret, i; + + /* If the I2C controller is disabled we need to reset it + (probably due to a suspend/resume destroying state). We do + this here as we can then avoid worrying about resuming the + controller before its users. */ + if (!(readl(_ICR(i2c)) & ICR_IUE)) + i2c_pxa_reset(i2c); + + for (i = adap->retries; i >= 0; i--) { + ret = i2c_pxa_do_pio_xfer(i2c, msgs, num); + if (ret != I2C_RETRY) + goto out; + + if (i2c_debug) + dev_dbg(&adap->dev, "Retrying transmission\n"); + udelay(100); + } + i2c_pxa_scream_blue_murder(i2c, "exhausted retries"); + ret = -EREMOTEIO; + out: + i2c_pxa_set_slave(i2c, ret); + return ret; +} + /* * i2c_pxa_master_complete - complete the message and wake up. */ @@ -621,7 +717,8 @@ static void i2c_pxa_master_complete(struct pxa_i2c *i2c, int ret) i2c->msg_num = 0; if (ret) i2c->msg_idx = ret; - wake_up(&i2c->wait); + if (!i2c->use_pio) + wake_up(&i2c->wait); } static void i2c_pxa_irq_txempty(struct pxa_i2c *i2c, u32 isr) @@ -840,6 +937,11 @@ static const struct i2c_algorithm i2c_pxa_algorithm = { .functionality = i2c_pxa_functionality, }; +static const struct i2c_algorithm i2c_pxa_pio_algorithm = { + .master_xfer = i2c_pxa_pio_xfer, + .functionality = i2c_pxa_functionality, +}; + static void i2c_pxa_enable(struct platform_device *dev) { if (cpu_is_pxa27x()) { @@ -890,7 +992,6 @@ static int i2c_pxa_probe(struct platform_device *dev) } i2c->adap.owner = THIS_MODULE; - i2c->adap.algo = &i2c_pxa_algorithm; i2c->adap.retries = 5; spin_lock_init(&i2c->lock); @@ -927,20 +1028,26 @@ static int i2c_pxa_probe(struct platform_device *dev) clk_enable(i2c->clk); i2c_pxa_enable(dev); - ret = request_irq(irq, i2c_pxa_handler, IRQF_DISABLED, - i2c->adap.name, i2c); - if (ret) - goto ereqirq; + if (plat) { + i2c->adap.class = plat->class; + i2c->use_pio = plat->use_pio; + } + + if (i2c->use_pio) { + i2c->adap.algo = &i2c_pxa_pio_algorithm; + } else { + i2c->adap.algo = &i2c_pxa_algorithm; + ret = request_irq(irq, i2c_pxa_handler, IRQF_DISABLED, + i2c->adap.name, i2c); + if (ret) + goto ereqirq; + } i2c_pxa_reset(i2c); i2c->adap.algo_data = i2c; i2c->adap.dev.parent = &dev->dev; - if (plat) { - i2c->adap.class = plat->class; - } - /* * If "dev->id" is negative we consider it as zero. * The reason to do so is to avoid sysfs names that only make @@ -966,7 +1073,8 @@ static int i2c_pxa_probe(struct platform_device *dev) return 0; eadapt: - free_irq(irq, i2c); + if (!i2c->use_pio) + free_irq(irq, i2c); ereqirq: clk_disable(i2c->clk); i2c_pxa_disable(dev); @@ -986,7 +1094,8 @@ static int i2c_pxa_remove(struct platform_device *dev) platform_set_drvdata(dev, NULL); i2c_del_adapter(&i2c->adap); - free_irq(i2c->irq, i2c); + if (!i2c->use_pio) + free_irq(i2c->irq, i2c); clk_disable(i2c->clk); clk_put(i2c->clk); -- cgit v1.2.3 From 0f07a24b4baf14859fde39b29bcc6fe279d18109 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sun, 27 Jan 2008 18:14:51 +0100 Subject: i2c: Let the user specify PCI driver data through new_id The i2c-amd756 and i2c-viapro drivers make use of the driver_data field of the PCI device ID. When adding device IDs dynamically (by writing to the new_id sysfs file) you cannot set the value of this field by default. It has to be allowed explicitly. Do that, and check the value so that the user can't crash the kernel accidentally. Signed-off-by: Jean Delvare Acked-by: Greg Kroah-Hartman --- drivers/i2c/busses/i2c-amd756.c | 5 +++++ drivers/i2c/busses/i2c-viapro.c | 5 +++++ 2 files changed, 10 insertions(+) (limited to 'drivers/i2c/busses') diff --git a/drivers/i2c/busses/i2c-amd756.c b/drivers/i2c/busses/i2c-amd756.c index 7490dc1771ae..573abe440842 100644 --- a/drivers/i2c/busses/i2c-amd756.c +++ b/drivers/i2c/busses/i2c-amd756.c @@ -334,6 +334,10 @@ static int __devinit amd756_probe(struct pci_dev *pdev, int error; u8 temp; + /* driver_data might come from user-space, so check it */ + if (id->driver_data > ARRAY_SIZE(chipname)) + return -EINVAL; + if (amd756_ioport) { dev_err(&pdev->dev, "Only one device supported " "(you have a strange motherboard, btw)\n"); @@ -405,6 +409,7 @@ static struct pci_driver amd756_driver = { .id_table = amd756_ids, .probe = amd756_probe, .remove = __devexit_p(amd756_remove), + .dynids.use_driver_data = 1, }; static int __init amd756_init(void) diff --git a/drivers/i2c/busses/i2c-viapro.c b/drivers/i2c/busses/i2c-viapro.c index c9ce77f13c0e..661ebc7a711e 100644 --- a/drivers/i2c/busses/i2c-viapro.c +++ b/drivers/i2c/busses/i2c-viapro.c @@ -318,6 +318,10 @@ static int __devinit vt596_probe(struct pci_dev *pdev, unsigned char temp; int error = -ENODEV; + /* driver_data might come from user-space, so check it */ + if (id->driver_data & 1 || id->driver_data > 0xff) + return -EINVAL; + /* Determine the address of the SMBus areas */ if (force_addr) { vt596_smba = force_addr & 0xfff0; @@ -455,6 +459,7 @@ static struct pci_driver vt596_driver = { .name = "vt596_smbus", .id_table = vt596_ids, .probe = vt596_probe, + .dynids.use_driver_data = 1, }; static int __init i2c_vt596_init(void) -- cgit v1.2.3 From 9b7389c0edb94a2623f21a6ac90afae63f201e73 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sun, 27 Jan 2008 18:14:51 +0100 Subject: i2c-piix4: Drop redundant PCI function number check Checking the PCI function number doesn't add any value, and it makes adding dynamic IDs to the driver more difficult. Drop this check. Signed-off-by: Jean Delvare --- drivers/i2c/busses/i2c-piix4.c | 41 +++++++++++++++-------------------------- 1 file changed, 15 insertions(+), 26 deletions(-) (limited to 'drivers/i2c/busses') diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c index 167e4137ee21..9bbe96cef719 100644 --- a/drivers/i2c/busses/i2c-piix4.c +++ b/drivers/i2c/busses/i2c-piix4.c @@ -121,10 +121,6 @@ static int __devinit piix4_setup(struct pci_dev *PIIX4_dev, { unsigned char temp; - /* match up the function */ - if (PCI_FUNC(PIIX4_dev->devfn) != id->driver_data) - return -ENODEV; - dev_info(&PIIX4_dev->dev, "Found %s device\n", pci_name(PIIX4_dev)); /* Don't access SMBus on IBM systems which get corrupted eeproms */ @@ -389,28 +385,21 @@ static struct i2c_adapter piix4_adapter = { }; static struct pci_device_id piix4_ids[] = { - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3), - .driver_data = 3 }, - { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP200_SMBUS), - .driver_data = 0 }, - { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP300_SMBUS), - .driver_data = 0 }, - { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP400_SMBUS), - .driver_data = 0 }, - { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_SBX00_SMBUS), - .driver_data = 0 }, - { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4), - .driver_data = 0 }, - { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5), - .driver_data = 0 }, - { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6), - .driver_data = 0 }, - { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_HT1000SB), - .driver_data = 0 }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_3), - .driver_data = 3 }, - { PCI_DEVICE(PCI_VENDOR_ID_EFAR, PCI_DEVICE_ID_EFAR_SLC90E66_3), - .driver_data = 0 }, + { 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) }, + { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP200_SMBUS) }, + { 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_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) }, { 0, } }; -- cgit v1.2.3 From 0d227a7e724460bddcd603a1feb672267bcb0d6c Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sun, 27 Jan 2008 18:14:51 +0100 Subject: i2c-viapro: Add support for the VT8237S Add support for another variant of the VT8237. I couldn't test I2C block support but I assume it is present as well. Signed-off-by: Jean Delvare --- drivers/i2c/busses/Kconfig | 2 +- drivers/i2c/busses/i2c-viapro.c | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers/i2c/busses') diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index a38ba04fe36e..8d12b26bb6c6 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -606,7 +606,7 @@ config I2C_VIAPRO VT8231 VT8233/A VT8235 - VT8237R/A + VT8237R/A/S VT8251 CX700 diff --git a/drivers/i2c/busses/i2c-viapro.c b/drivers/i2c/busses/i2c-viapro.c index 661ebc7a711e..77b13d027f86 100644 --- a/drivers/i2c/busses/i2c-viapro.c +++ b/drivers/i2c/busses/i2c-viapro.c @@ -4,7 +4,7 @@ Copyright (c) 1998 - 2002 Frodo Looijaard , Philip Edelbrock , Kyösti Mälkki , Mark D. Studebaker - Copyright (C) 2005 - 2007 Jean Delvare + Copyright (C) 2005 - 2008 Jean Delvare 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 @@ -35,6 +35,7 @@ VT8235 0x3177 yes VT8237R 0x3227 yes VT8237A 0x3337 yes + VT8237S 0x3372 yes VT8251 0x3287 yes CX700 0x8324 yes @@ -393,6 +394,7 @@ found: case PCI_DEVICE_ID_VIA_8251: case PCI_DEVICE_ID_VIA_8237: case PCI_DEVICE_ID_VIA_8237A: + case PCI_DEVICE_ID_VIA_8237S: case PCI_DEVICE_ID_VIA_8235: case PCI_DEVICE_ID_VIA_8233A: case PCI_DEVICE_ID_VIA_8233_0: @@ -444,6 +446,8 @@ static struct pci_device_id vt596_ids[] = { .driver_data = SMBBA3 }, { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237A), .driver_data = SMBBA3 }, + { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237S), + .driver_data = SMBBA3 }, { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8231_4), .driver_data = SMBBA1 }, { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8251), -- cgit v1.2.3 From 4bd28ebda2d48f16c1f16ff936a6927a4ef2194d Mon Sep 17 00:00:00 2001 From: Jon Smirl Date: Sun, 27 Jan 2008 18:14:52 +0100 Subject: mpc-i2c: Propagate error values properly Propagate the error values returned by i2c_wait() instead of overriding them with a meaningless -1. Signed-off-by: Jon Smirl Signed-off-by: Jean Delvare --- drivers/i2c/busses/i2c-mpc.c | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) (limited to 'drivers/i2c/busses') diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c index 81335b76c425..bbe787b243b7 100644 --- a/drivers/i2c/busses/i2c-mpc.c +++ b/drivers/i2c/busses/i2c-mpc.c @@ -180,7 +180,7 @@ static void mpc_i2c_stop(struct mpc_i2c *i2c) static int mpc_write(struct mpc_i2c *i2c, int target, const u8 * data, int length, int restart) { - int i; + int i, result; unsigned timeout = i2c->adap.timeout; u32 flags = restart ? CCR_RSTA : 0; @@ -192,15 +192,17 @@ static int mpc_write(struct mpc_i2c *i2c, int target, /* Write target byte */ writeb((target << 1), i2c->base + MPC_I2C_DR); - if (i2c_wait(i2c, timeout, 1) < 0) - return -1; + result = i2c_wait(i2c, timeout, 1); + if (result < 0) + return result; for (i = 0; i < length; i++) { /* Write data byte */ writeb(data[i], i2c->base + MPC_I2C_DR); - if (i2c_wait(i2c, timeout, 1) < 0) - return -1; + result = i2c_wait(i2c, timeout, 1); + if (result < 0) + return result; } return 0; @@ -210,7 +212,7 @@ static int mpc_read(struct mpc_i2c *i2c, int target, u8 * data, int length, int restart) { unsigned timeout = i2c->adap.timeout; - int i; + int i, result; u32 flags = restart ? CCR_RSTA : 0; /* Start with MEN */ @@ -221,8 +223,9 @@ static int mpc_read(struct mpc_i2c *i2c, int target, /* Write target address byte - this time with the read flag set */ writeb((target << 1) | 1, i2c->base + MPC_I2C_DR); - if (i2c_wait(i2c, timeout, 1) < 0) - return -1; + result = i2c_wait(i2c, timeout, 1); + if (result < 0) + return result; if (length) { if (length == 1) @@ -234,8 +237,9 @@ static int mpc_read(struct mpc_i2c *i2c, int target, } for (i = 0; i < length; i++) { - if (i2c_wait(i2c, timeout, 0) < 0) - return -1; + result = i2c_wait(i2c, timeout, 0); + if (result < 0) + return result; /* Generate txack on next to last byte */ if (i == length - 2) @@ -320,9 +324,9 @@ static int fsl_i2c_probe(struct platform_device *pdev) pdata = (struct fsl_i2c_platform_data *) pdev->dev.platform_data; - if (!(i2c = kzalloc(sizeof(*i2c), GFP_KERNEL))) { + i2c = kzalloc(sizeof(*i2c), GFP_KERNEL); + if (!i2c) return -ENOMEM; - } i2c->irq = platform_get_irq(pdev, 0); if (i2c->irq < 0) { -- cgit v1.2.3 From 91f27958d686da713c3b0a1dc205288898e44124 Mon Sep 17 00:00:00 2001 From: Manuel Lauss Date: Sun, 27 Jan 2008 18:14:52 +0100 Subject: i2c-au1550: properly terminate zero-byte transfers Zero-bytes transfers would leave the bus transaction unfinished (no i2c stop is sent), with the following transfer actually sending the slave address to the previously addressed device, resulting in weird device failures (e.g. reset minute register values in my RTC). This patch instructs the controller to send an I2C STOP right after the slave address in case of a zero-byte transfer. Signed-off-by: Manuel Lauss Signed-off-by: Jean Delvare --- drivers/i2c/busses/i2c-au1550.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'drivers/i2c/busses') diff --git a/drivers/i2c/busses/i2c-au1550.c b/drivers/i2c/busses/i2c-au1550.c index 2f684166c43d..7d51a43b38d3 100644 --- a/drivers/i2c/busses/i2c-au1550.c +++ b/drivers/i2c/busses/i2c-au1550.c @@ -105,7 +105,7 @@ wait_master_done(struct i2c_au1550_data *adap) } static int -do_address(struct i2c_au1550_data *adap, unsigned int addr, int rd) +do_address(struct i2c_au1550_data *adap, unsigned int addr, int rd, int q) { volatile psc_smb_t *sp; u32 stat; @@ -134,6 +134,10 @@ do_address(struct i2c_au1550_data *adap, unsigned int addr, int rd) if (rd) addr |= 1; + /* zero-byte xfers stop immediately */ + if (q) + addr |= PSC_SMBTXRX_STP; + /* Put byte into fifo, start up master. */ sp->psc_smbtxrx = addr; @@ -142,7 +146,7 @@ do_address(struct i2c_au1550_data *adap, unsigned int addr, int rd) au_sync(); if (wait_ack(adap)) return -EIO; - return 0; + return (q) ? wait_master_done(adap) : 0; } static u32 @@ -262,7 +266,8 @@ au1550_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num) for (i = 0; !err && i < num; i++) { p = &msgs[i]; - err = do_address(adap, p->addr, p->flags & I2C_M_RD); + err = do_address(adap, p->addr, p->flags & I2C_M_RD, + (p->len == 0)); if (err || !p->len) continue; if (p->flags & I2C_M_RD) -- cgit v1.2.3 From 8b798c4d16b762d15f4055597ff8d87f73b35552 Mon Sep 17 00:00:00 2001 From: Manuel Lauss Date: Sun, 27 Jan 2008 18:14:52 +0100 Subject: i2c-au1550: Convert to platform driver Convert the i2c-au1550 bus driver to platform driver, and register a platform device for the Alchemy Db/Pb series of boards. Signed-off-by: Manuel Lauss Signed-off-by: Jean Delvare --- drivers/i2c/busses/i2c-au1550.c | 166 ++++++++++++++++++++++++---------------- drivers/i2c/busses/i2c-au1550.h | 32 -------- 2 files changed, 102 insertions(+), 96 deletions(-) delete mode 100644 drivers/i2c/busses/i2c-au1550.h (limited to 'drivers/i2c/busses') diff --git a/drivers/i2c/busses/i2c-au1550.c b/drivers/i2c/busses/i2c-au1550.c index 7d51a43b38d3..1953b26da56a 100644 --- a/drivers/i2c/busses/i2c-au1550.c +++ b/drivers/i2c/busses/i2c-au1550.c @@ -30,14 +30,22 @@ #include #include #include +#include #include #include #include +#include #include #include -#include "i2c-au1550.h" +struct i2c_au1550_data { + u32 psc_base; + int xfer_timeout; + int ack_timeout; + struct i2c_adapter adap; + struct resource *ioarea; +}; static int wait_xfer_done(struct i2c_au1550_data *adap) @@ -299,18 +307,48 @@ static const struct i2c_algorithm au1550_algo = { * Prior to calling us, the 50MHz clock frequency and routing * must have been set up for the PSC indicated by the adapter. */ -int -i2c_au1550_add_bus(struct i2c_adapter *i2c_adap) +static int __devinit +i2c_au1550_probe(struct platform_device *pdev) { - struct i2c_au1550_data *adap = i2c_adap->algo_data; - volatile psc_smb_t *sp; - u32 stat; + struct i2c_au1550_data *priv; + volatile psc_smb_t *sp; + struct resource *r; + u32 stat; + int ret; + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!r) { + ret = -ENODEV; + goto out; + } - i2c_adap->algo = &au1550_algo; + priv = kzalloc(sizeof(struct i2c_au1550_data), GFP_KERNEL); + if (!priv) { + ret = -ENOMEM; + goto out; + } + + priv->ioarea = request_mem_region(r->start, r->end - r->start + 1, + pdev->name); + if (!priv->ioarea) { + ret = -EBUSY; + goto out_mem; + } + + priv->psc_base = r->start; + priv->xfer_timeout = 200; + priv->ack_timeout = 200; + + priv->adap.id = I2C_HW_AU1550_PSC; + priv->adap.nr = pdev->id; + priv->adap.algo = &au1550_algo; + priv->adap.algo_data = priv; + priv->adap.dev.parent = &pdev->dev; + strlcpy(priv->adap.name, "Au1xxx PSC I2C", sizeof(priv->adap.name)); /* Now, set up the PSC for SMBus PIO mode. */ - sp = (volatile psc_smb_t *)(adap->psc_base); + sp = (volatile psc_smb_t *)priv->psc_base; sp->psc_ctrl = PSC_CTRL_DISABLE; au_sync(); sp->psc_sel = PSC_SEL_PS_SMBUSMODE; @@ -348,87 +386,87 @@ i2c_au1550_add_bus(struct i2c_adapter *i2c_adap) au_sync(); } while ((stat & PSC_SMBSTAT_DR) == 0); - return i2c_add_adapter(i2c_adap); -} + ret = i2c_add_numbered_adapter(&priv->adap); + if (ret == 0) { + platform_set_drvdata(pdev, priv); + return 0; + } + + /* disable the PSC */ + sp->psc_smbcfg = 0; + sp->psc_ctrl = PSC_CTRL_DISABLE; + au_sync(); + release_resource(priv->ioarea); + kfree(priv->ioarea); +out_mem: + kfree(priv); +out: + return ret; +} -int -i2c_au1550_del_bus(struct i2c_adapter *adap) +static int __devexit +i2c_au1550_remove(struct platform_device *pdev) { - return i2c_del_adapter(adap); + struct i2c_au1550_data *priv = platform_get_drvdata(pdev); + volatile psc_smb_t *sp = (volatile psc_smb_t *)priv->psc_base; + + platform_set_drvdata(pdev, NULL); + i2c_del_adapter(&priv->adap); + sp->psc_smbcfg = 0; + sp->psc_ctrl = PSC_CTRL_DISABLE; + au_sync(); + release_resource(priv->ioarea); + kfree(priv->ioarea); + kfree(priv); + return 0; } static int -pb1550_reg(struct i2c_client *client) +i2c_au1550_suspend(struct platform_device *pdev, pm_message_t state) { + struct i2c_au1550_data *priv = platform_get_drvdata(pdev); + volatile psc_smb_t *sp = (volatile psc_smb_t *)priv->psc_base; + + sp->psc_ctrl = PSC_CTRL_SUSPEND; + au_sync(); return 0; } static int -pb1550_unreg(struct i2c_client *client) +i2c_au1550_resume(struct platform_device *pdev) { + struct i2c_au1550_data *priv = platform_get_drvdata(pdev); + volatile psc_smb_t *sp = (volatile psc_smb_t *)priv->psc_base; + + sp->psc_ctrl = PSC_CTRL_ENABLE; + au_sync(); + while (!(sp->psc_smbstat & PSC_SMBSTAT_SR)) + au_sync(); return 0; } -static struct i2c_au1550_data pb1550_i2c_info = { - SMBUS_PSC_BASE, 200, 200 -}; - -static struct i2c_adapter pb1550_board_adapter = { - name: "pb1550 adapter", - id: I2C_HW_AU1550_PSC, - algo: NULL, - algo_data: &pb1550_i2c_info, - client_register: pb1550_reg, - client_unregister: pb1550_unreg, +static struct platform_driver au1xpsc_smbus_driver = { + .driver = { + .name = "au1xpsc_smbus", + .owner = THIS_MODULE, + }, + .probe = i2c_au1550_probe, + .remove = __devexit_p(i2c_au1550_remove), + .suspend = i2c_au1550_suspend, + .resume = i2c_au1550_resume, }; -/* BIG hack to support the control interface on the Wolfson WM8731 - * audio codec on the Pb1550 board. We get an address and two data - * bytes to write, create an i2c message, and send it across the - * i2c transfer function. We do this here because we have access to - * the i2c adapter structure. - */ -static struct i2c_msg wm_i2c_msg; /* We don't want this stuff on the stack */ -static u8 i2cbuf[2]; - -int -pb1550_wm_codec_write(u8 addr, u8 reg, u8 val) -{ - wm_i2c_msg.addr = addr; - wm_i2c_msg.flags = 0; - wm_i2c_msg.buf = i2cbuf; - wm_i2c_msg.len = 2; - i2cbuf[0] = reg; - i2cbuf[1] = val; - - return pb1550_board_adapter.algo->master_xfer(&pb1550_board_adapter, &wm_i2c_msg, 1); -} - static int __init i2c_au1550_init(void) { - printk(KERN_INFO "Au1550 I2C: "); - - /* This is where we would set up a 50MHz clock source - * and routing. On the Pb1550, the SMBus is PSC2, which - * uses a shared clock with USB. This has been already - * configured by Yamon as a 48MHz clock, close enough - * for our work. - */ - if (i2c_au1550_add_bus(&pb1550_board_adapter) < 0) { - printk("failed to initialize.\n"); - return -ENODEV; - } - - printk("initialized.\n"); - return 0; + return platform_driver_register(&au1xpsc_smbus_driver); } static void __exit i2c_au1550_exit(void) { - i2c_au1550_del_bus(&pb1550_board_adapter); + platform_driver_unregister(&au1xpsc_smbus_driver); } MODULE_AUTHOR("Dan Malek, Embedded Edge, LLC."); diff --git a/drivers/i2c/busses/i2c-au1550.h b/drivers/i2c/busses/i2c-au1550.h deleted file mode 100644 index fce15d161ae7..000000000000 --- a/drivers/i2c/busses/i2c-au1550.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (C) 2004 Embedded Edge, LLC - * 2.6 port by Matt Porter - * - * 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. - */ - -#ifndef I2C_AU1550_H -#define I2C_AU1550_H - -struct i2c_au1550_data { - u32 psc_base; - int xfer_timeout; - int ack_timeout; -}; - -int i2c_au1550_add_bus(struct i2c_adapter *); -int i2c_au1550_del_bus(struct i2c_adapter *); - -#endif /* I2C_AU1550_H */ -- cgit v1.2.3 From 991dee591a99d035796a8c194eb1796cc020e142 Mon Sep 17 00:00:00 2001 From: Kalle Pokki Date: Sun, 27 Jan 2008 18:14:52 +0100 Subject: i2c-bfin-twi: Register adapter with a specific bus number All the users of this driver explicitly specify the I2C bus numbers to be used in their platform data. Make the driver respect that. Signed-off-by: Kalle Pokki Cc: Bryan Wu Signed-off-by: Jean Delvare --- drivers/i2c/busses/i2c-bfin-twi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/i2c/busses') diff --git a/drivers/i2c/busses/i2c-bfin-twi.c b/drivers/i2c/busses/i2c-bfin-twi.c index 67224a424aba..7dbdaeb707a9 100644 --- a/drivers/i2c/busses/i2c-bfin-twi.c +++ b/drivers/i2c/busses/i2c-bfin-twi.c @@ -550,6 +550,7 @@ static int i2c_bfin_twi_probe(struct platform_device *dev) p_adap = &iface->adap; p_adap->id = I2C_HW_BLACKFIN; + p_adap->nr = dev->id; strlcpy(p_adap->name, dev->name, sizeof(p_adap->name)); p_adap->algo = &bfin_twi_algorithm; p_adap->algo_data = iface; @@ -576,7 +577,7 @@ static int i2c_bfin_twi_probe(struct platform_device *dev) bfin_write_TWI_CONTROL(bfin_read_TWI_CONTROL() | TWI_ENA); SSYNC(); - rc = i2c_add_adapter(p_adap); + rc = i2c_add_numbered_adapter(p_adap); if (rc < 0) free_irq(iface->irq, iface); else -- cgit v1.2.3