From 51fd554b6547b74c7e6d1f52885ba8532b531023 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sun, 10 Dec 2006 21:21:29 +0100 Subject: i2c: Delete the broken i2c-ite bus driver The rest of the ITE8172 support was already removed from MIPS tree. Signed-off-by: Jean Delvare Signed-off-by: Yoichi Yuasa Acked-by: Ralf Baechle --- drivers/i2c/busses/Kconfig | 12 -- drivers/i2c/busses/Makefile | 1 - drivers/i2c/busses/i2c-ite.c | 278 ------------------------------------------- 3 files changed, 291 deletions(-) delete mode 100644 drivers/i2c/busses/i2c-ite.c (limited to 'drivers/i2c/busses') diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 90f91d039ee..7c9ab337d18 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -209,18 +209,6 @@ config I2C_ISA tristate depends on I2C -config I2C_ITE - tristate "ITE I2C Adapter" - depends on I2C && MIPS_ITE8172 - select I2C_ALGOITE - help - This supports the ITE8172 I2C peripheral found on some MIPS - systems. Say Y if you have one of these. You should also say Y for - the ITE I2C driver algorithm support above. - - This support is also available as a module. If so, the module - will be called i2c-ite. - config I2C_IXP4XX tristate "IXP4xx GPIO-Based I2C Interface" depends on I2C && ARCH_IXP4XX diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 493c87289b6..bf5fd078b29 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -16,7 +16,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_ISA) += i2c-isa.o -obj-$(CONFIG_I2C_ITE) += i2c-ite.o obj-$(CONFIG_I2C_IXP2000) += i2c-ixp2000.o obj-$(CONFIG_I2C_IXP4XX) += i2c-ixp4xx.o obj-$(CONFIG_I2C_POWERMAC) += i2c-powermac.o diff --git a/drivers/i2c/busses/i2c-ite.c b/drivers/i2c/busses/i2c-ite.c deleted file mode 100644 index f7d71869b3b..00000000000 --- a/drivers/i2c/busses/i2c-ite.c +++ /dev/null @@ -1,278 +0,0 @@ -/* - ------------------------------------------------------------------------- - i2c-adap-ite.c i2c-hw access for the IIC peripheral on the ITE MIPS system - ------------------------------------------------------------------------- - Hai-Pao Fan, MontaVista Software, Inc. - hpfan@mvista.com or source@mvista.com - - Copyright 2001 MontaVista Software Inc. - - ---------------------------------------------------------------------------- - This file was highly leveraged from i2c-elektor.c, which was created - by Simon G. Vogl and Hans Berglund: - - - Copyright (C) 1995-97 Simon G. Vogl - 1998-99 Hans Berglund - - 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. */ -/* ------------------------------------------------------------------------- */ - -/* With some changes from Kyösti Mälkki and even - Frodo Looijaard */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include "../i2c-ite.h" - -#define DEFAULT_BASE 0x14014030 -#define ITE_IIC_IO_SIZE 0x40 -#define DEFAULT_IRQ 0 -#define DEFAULT_CLOCK 0x1b0e /* default 16MHz/(27+14) = 400KHz */ -#define DEFAULT_OWN 0x55 - -static int base; -static int irq; -static int clock; -static int own; - -static struct iic_ite gpi; -static wait_queue_head_t iic_wait; -static int iic_pending; -static spinlock_t lock; - -/* ----- local functions ---------------------------------------------- */ - -static void iic_ite_setiic(void *data, int ctl, short val) -{ - unsigned long j = jiffies + 10; - - pr_debug(" Write 0x%02x to 0x%x\n",(unsigned short)val, ctl&0xff); -#ifdef DEBUG - while (time_before(jiffies, j)) - schedule(); -#endif - outw(val,ctl); -} - -static short iic_ite_getiic(void *data, int ctl) -{ - short val; - - val = inw(ctl); - pr_debug("Read 0x%02x from 0x%x\n",(unsigned short)val, ctl&0xff); - return (val); -} - -/* Return our slave address. This is the address - * put on the I2C bus when another master on the bus wants to address us - * as a slave - */ -static int iic_ite_getown(void *data) -{ - return (gpi.iic_own); -} - - -static int iic_ite_getclock(void *data) -{ - return (gpi.iic_clock); -} - - -/* Put this process to sleep. We will wake up when the - * IIC controller interrupts. - */ -static void iic_ite_waitforpin(void) { - DEFINE_WAIT(wait); - int timeout = 2; - unsigned long flags; - - /* If interrupts are enabled (which they are), then put the process to - * sleep. This process will be awakened by two events -- either the - * the IIC peripheral interrupts or the timeout expires. - * If interrupts are not enabled then delay for a reasonable amount - * of time and return. - */ - if (gpi.iic_irq > 0) { - spin_lock_irqsave(&lock, flags); - if (iic_pending == 0) { - spin_unlock_irqrestore(&lock, flags); - prepare_to_wait(&iic_wait, &wait, TASK_INTERRUPTIBLE); - if (schedule_timeout(timeout*HZ)) { - spin_lock_irqsave(&lock, flags); - if (iic_pending == 1) { - iic_pending = 0; - } - spin_unlock_irqrestore(&lock, flags); - } - finish_wait(&iic_wait, &wait); - } else { - iic_pending = 0; - spin_unlock_irqrestore(&lock, flags); - } - } else { - udelay(100); - } -} - - -static irqreturn_t iic_ite_handler(int this_irq, void *dev_id) -{ - spin_lock(&lock); - iic_pending = 1; - spin_unlock(&lock); - - wake_up_interruptible(&iic_wait); - - return IRQ_HANDLED; -} - - -/* Lock the region of memory where I/O registers exist. Request our - * interrupt line and register its associated handler. - */ -static int iic_hw_resrc_init(void) -{ - if (!request_region(gpi.iic_base, ITE_IIC_IO_SIZE, "i2c")) - return -ENODEV; - - if (gpi.iic_irq <= 0) - return 0; - - if (request_irq(gpi.iic_irq, iic_ite_handler, 0, "ITE IIC", 0) < 0) - gpi.iic_irq = 0; - else - enable_irq(gpi.iic_irq); - - return 0; -} - - -static void iic_ite_release(void) -{ - if (gpi.iic_irq > 0) { - disable_irq(gpi.iic_irq); - free_irq(gpi.iic_irq, 0); - } - release_region(gpi.iic_base , 2); -} - -/* ------------------------------------------------------------------------ - * Encapsulate the above functions in the correct operations structure. - * This is only done when more than one hardware adapter is supported. - */ -static struct i2c_algo_iic_data iic_ite_data = { - NULL, - iic_ite_setiic, - iic_ite_getiic, - iic_ite_getown, - iic_ite_getclock, - iic_ite_waitforpin, - 80, 80, 100, /* waits, timeout */ -}; - -static struct i2c_adapter iic_ite_ops = { - .owner = THIS_MODULE, - .id = I2C_HW_I_IIC, - .algo_data = &iic_ite_data, - .name = "ITE IIC adapter", -}; - -/* Called when the module is loaded. This function starts the - * cascade of calls up through the hierarchy of i2c modules (i.e. up to the - * algorithm layer and into to the core layer) - */ -static int __init iic_ite_init(void) -{ - - struct iic_ite *piic = &gpi; - - printk(KERN_INFO "Initialize ITE IIC adapter module\n"); - if (base == 0) - piic->iic_base = DEFAULT_BASE; - else - piic->iic_base = base; - - if (irq == 0) - piic->iic_irq = DEFAULT_IRQ; - else - piic->iic_irq = irq; - - if (clock == 0) - piic->iic_clock = DEFAULT_CLOCK; - else - piic->iic_clock = clock; - - if (own == 0) - piic->iic_own = DEFAULT_OWN; - else - piic->iic_own = own; - - iic_ite_data.data = (void *)piic; - init_waitqueue_head(&iic_wait); - spin_lock_init(&lock); - if (iic_hw_resrc_init() == 0) { - if (i2c_iic_add_bus(&iic_ite_ops) < 0) - return -ENODEV; - } else { - return -ENODEV; - } - printk(KERN_INFO " found device at %#x irq %d.\n", - piic->iic_base, piic->iic_irq); - return 0; -} - - -static void iic_ite_exit(void) -{ - i2c_iic_del_bus(&iic_ite_ops); - iic_ite_release(); -} - -/* If modules is NOT defined when this file is compiled, then the MODULE_* - * macros will resolve to nothing - */ -MODULE_AUTHOR("MontaVista Software "); -MODULE_DESCRIPTION("I2C-Bus adapter routines for ITE IIC bus adapter"); -MODULE_LICENSE("GPL"); - -module_param(base, int, 0); -module_param(irq, int, 0); -module_param(clock, int, 0); -module_param(own, int, 0); - - -/* Called when module is loaded or when kernel is initialized. - * If MODULES is defined when this file is compiled, then this function will - * resolve to init_module (the function called when insmod is invoked for a - * module). Otherwise, this function is called early in the boot, when the - * kernel is intialized. Check out /include/init.h to see how this works. - */ -module_init(iic_ite_init); - -/* Resolves to module_cleanup when MODULES is defined. */ -module_exit(iic_ite_exit); -- cgit v1.2.3 From 41561f28e76a47dc6de0a954da85d0b5c42874eb Mon Sep 17 00:00:00 2001 From: Vitaly Wool Date: Sun, 10 Dec 2006 21:21:29 +0100 Subject: i2c: New Philips PNX bus driver New I2C bus driver for Philips ARM boards (Philips IP3204 I2C IP block). This I2C controller can be found on (at least) PNX010x, PNX52xx and PNX4008 Philips boards. Signed-off-by: Vitaly Wool Signed-off-by: Jean Delvare --- drivers/i2c/busses/Kconfig | 19 ++ drivers/i2c/busses/Makefile | 1 + drivers/i2c/busses/i2c-pnx.c | 708 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 728 insertions(+) create mode 100644 drivers/i2c/busses/i2c-pnx.c (limited to 'drivers/i2c/busses') diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 7c9ab337d18..291da25e84d 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -536,4 +536,23 @@ config I2C_MV64XXX This driver can also be built as a module. If so, the module will be called i2c-mv64xxx. +config I2C_PNX + tristate "I2C bus support for Philips PNX targets" + depends on ARCH_PNX4008 && I2C + help + This driver supports the Philips IP3204 I2C IP block master and/or + slave controller + + This driver can also be built as a module. If so, the module + will be called i2c-pnx. + +config I2C_PNX_EARLY + bool "Early initialization for I2C on PNXxxxx" + depends on I2C_PNX=y + help + Under certain circumstances one may need to make sure I2C on PNXxxxx + is initialized earlier than some other driver that depends on it + (for instance, that might be USB in case of PNX4008). With this + option turned on you can guarantee that. + endmenu diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index bf5fd078b29..626ac71af95 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -28,6 +28,7 @@ obj-$(CONFIG_I2C_PARPORT) += i2c-parport.o obj-$(CONFIG_I2C_PARPORT_LIGHT) += i2c-parport-light.o obj-$(CONFIG_I2C_PCA_ISA) += i2c-pca-isa.o obj-$(CONFIG_I2C_PIIX4) += i2c-piix4.o +obj-$(CONFIG_I2C_PNX) += i2c-pnx.o obj-$(CONFIG_I2C_PROSAVAGE) += i2c-prosavage.o obj-$(CONFIG_I2C_PXA) += i2c-pxa.o obj-$(CONFIG_I2C_RPXLITE) += i2c-rpx.o diff --git a/drivers/i2c/busses/i2c-pnx.c b/drivers/i2c/busses/i2c-pnx.c new file mode 100644 index 00000000000..de0bca77e92 --- /dev/null +++ b/drivers/i2c/busses/i2c-pnx.c @@ -0,0 +1,708 @@ +/* + * Provides I2C support for Philips PNX010x/PNX4008 boards. + * + * Authors: Dennis Kovalev + * Vitaly Wool + * + * 2004-2006 (c) 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define I2C_PNX_TIMEOUT 10 /* msec */ +#define I2C_PNX_SPEED_KHZ 100 +#define I2C_PNX_REGION_SIZE 0x100 +#define PNX_DEFAULT_FREQ 13 /* MHz */ + +static inline int wait_timeout(long timeout, struct i2c_pnx_algo_data *data) +{ + while (timeout > 0 && + (ioread32(I2C_REG_STS(data)) & mstatus_active)) { + mdelay(1); + timeout--; + } + return (timeout <= 0); +} + +static inline int wait_reset(long timeout, struct i2c_pnx_algo_data *data) +{ + while (timeout > 0 && + (ioread32(I2C_REG_CTL(data)) & mcntrl_reset)) { + mdelay(1); + timeout--; + } + return (timeout <= 0); +} + +static inline void i2c_pnx_arm_timer(struct i2c_adapter *adap) +{ + struct i2c_pnx_algo_data *data = adap->algo_data; + struct timer_list *timer = &data->mif.timer; + int expires = I2C_PNX_TIMEOUT / (1000 / HZ); + + del_timer_sync(timer); + + dev_dbg(&adap->dev, "Timer armed at %lu plus %u jiffies.\n", + jiffies, expires); + + timer->expires = jiffies + expires; + timer->data = (unsigned long)adap; + + add_timer(timer); +} + +/** + * i2c_pnx_start - start a device + * @slave_addr: slave address + * @adap: pointer to adapter structure + * + * Generate a START signal in the desired mode. + */ +static int i2c_pnx_start(unsigned char slave_addr, struct i2c_adapter *adap) +{ + struct i2c_pnx_algo_data *alg_data = adap->algo_data; + + dev_dbg(&adap->dev, "%s(): addr 0x%x mode %d\n", __FUNCTION__, + slave_addr, alg_data->mif.mode); + + /* Check for 7 bit slave addresses only */ + if (slave_addr & ~0x7f) { + dev_err(&adap->dev, "%s: Invalid slave address %x. " + "Only 7-bit addresses are supported\n", + adap->name, slave_addr); + return -EINVAL; + } + + /* First, make sure bus is idle */ + if (wait_timeout(I2C_PNX_TIMEOUT, alg_data)) { + /* Somebody else is monopolizing the bus */ + dev_err(&adap->dev, "%s: Bus busy. Slave addr = %02x, " + "cntrl = %x, stat = %x\n", + adap->name, slave_addr, + ioread32(I2C_REG_CTL(alg_data)), + ioread32(I2C_REG_STS(alg_data))); + return -EBUSY; + } else if (ioread32(I2C_REG_STS(alg_data)) & mstatus_afi) { + /* Sorry, we lost the bus */ + dev_err(&adap->dev, "%s: Arbitration failure. " + "Slave addr = %02x\n", adap->name, slave_addr); + return -EIO; + } + + /* + * OK, I2C is enabled and we have the bus. + * Clear the current TDI and AFI status flags. + */ + iowrite32(ioread32(I2C_REG_STS(alg_data)) | mstatus_tdi | mstatus_afi, + I2C_REG_STS(alg_data)); + + dev_dbg(&adap->dev, "%s(): sending %#x\n", __FUNCTION__, + (slave_addr << 1) | start_bit | alg_data->mif.mode); + + /* Write the slave address, START bit and R/W bit */ + iowrite32((slave_addr << 1) | start_bit | alg_data->mif.mode, + I2C_REG_TX(alg_data)); + + dev_dbg(&adap->dev, "%s(): exit\n", __FUNCTION__); + + return 0; +} + +/** + * i2c_pnx_stop - stop a device + * @adap: pointer to I2C adapter structure + * + * Generate a STOP signal to terminate the master transaction. + */ +static void i2c_pnx_stop(struct i2c_adapter *adap) +{ + struct i2c_pnx_algo_data *alg_data = adap->algo_data; + /* Only 1 msec max timeout due to interrupt context */ + long timeout = 1000; + + dev_dbg(&adap->dev, "%s(): entering: stat = %04x.\n", + __FUNCTION__, ioread32(I2C_REG_STS(alg_data))); + + /* Write a STOP bit to TX FIFO */ + iowrite32(0xff | stop_bit, I2C_REG_TX(alg_data)); + + /* Wait until the STOP is seen. */ + while (timeout > 0 && + (ioread32(I2C_REG_STS(alg_data)) & mstatus_active)) { + /* may be called from interrupt context */ + udelay(1); + timeout--; + } + + dev_dbg(&adap->dev, "%s(): exiting: stat = %04x.\n", + __FUNCTION__, ioread32(I2C_REG_STS(alg_data))); +} + +/** + * i2c_pnx_master_xmit - transmit data to slave + * @adap: pointer to I2C adapter structure + * + * Sends one byte of data to the slave + */ +static int i2c_pnx_master_xmit(struct i2c_adapter *adap) +{ + struct i2c_pnx_algo_data *alg_data = adap->algo_data; + u32 val; + + dev_dbg(&adap->dev, "%s(): entering: stat = %04x.\n", + __FUNCTION__, ioread32(I2C_REG_STS(alg_data))); + + if (alg_data->mif.len > 0) { + /* We still have something to talk about... */ + val = *alg_data->mif.buf++; + + if (alg_data->mif.len == 1) { + val |= stop_bit; + if (!alg_data->last) + val |= start_bit; + } + + alg_data->mif.len--; + iowrite32(val, I2C_REG_TX(alg_data)); + + dev_dbg(&adap->dev, "%s(): xmit %#x [%d]\n", __FUNCTION__, + val, alg_data->mif.len + 1); + + if (alg_data->mif.len == 0) { + if (alg_data->last) { + /* Wait until the STOP is seen. */ + if (wait_timeout(I2C_PNX_TIMEOUT, alg_data)) + dev_err(&adap->dev, "The bus is still " + "active after timeout\n"); + } + /* Disable master interrupts */ + iowrite32(ioread32(I2C_REG_CTL(alg_data)) & + ~(mcntrl_afie | mcntrl_naie | mcntrl_drmie), + I2C_REG_CTL(alg_data)); + + del_timer_sync(&alg_data->mif.timer); + + dev_dbg(&adap->dev, "%s(): Waking up xfer routine.\n", + __FUNCTION__); + + complete(&alg_data->mif.complete); + } + } else if (alg_data->mif.len == 0) { + /* zero-sized transfer */ + i2c_pnx_stop(adap); + + /* Disable master interrupts. */ + iowrite32(ioread32(I2C_REG_CTL(alg_data)) & + ~(mcntrl_afie | mcntrl_naie | mcntrl_drmie), + I2C_REG_CTL(alg_data)); + + /* Stop timer. */ + del_timer_sync(&alg_data->mif.timer); + dev_dbg(&adap->dev, "%s(): Waking up xfer routine after " + "zero-xfer.\n", __FUNCTION__); + + complete(&alg_data->mif.complete); + } + + dev_dbg(&adap->dev, "%s(): exiting: stat = %04x.\n", + __FUNCTION__, ioread32(I2C_REG_STS(alg_data))); + + return 0; +} + +/** + * i2c_pnx_master_rcv - receive data from slave + * @adap: pointer to I2C adapter structure + * + * Reads one byte data from the slave + */ +static int i2c_pnx_master_rcv(struct i2c_adapter *adap) +{ + struct i2c_pnx_algo_data *alg_data = adap->algo_data; + unsigned int val = 0; + u32 ctl = 0; + + dev_dbg(&adap->dev, "%s(): entering: stat = %04x.\n", + __FUNCTION__, ioread32(I2C_REG_STS(alg_data))); + + /* Check, whether there is already data, + * or we didn't 'ask' for it yet. + */ + if (ioread32(I2C_REG_STS(alg_data)) & mstatus_rfe) { + dev_dbg(&adap->dev, "%s(): Write dummy data to fill " + "Rx-fifo...\n", __FUNCTION__); + + if (alg_data->mif.len == 1) { + /* Last byte, do not acknowledge next rcv. */ + val |= stop_bit; + if (!alg_data->last) + val |= start_bit; + + /* + * Enable interrupt RFDAIE (data in Rx fifo), + * and disable DRMIE (need data for Tx) + */ + ctl = ioread32(I2C_REG_CTL(alg_data)); + ctl |= mcntrl_rffie | mcntrl_daie; + ctl &= ~mcntrl_drmie; + iowrite32(ctl, I2C_REG_CTL(alg_data)); + } + + /* + * Now we'll 'ask' for data: + * For each byte we want to receive, we must + * write a (dummy) byte to the Tx-FIFO. + */ + iowrite32(val, I2C_REG_TX(alg_data)); + + return 0; + } + + /* Handle data. */ + if (alg_data->mif.len > 0) { + val = ioread32(I2C_REG_RX(alg_data)); + *alg_data->mif.buf++ = (u8) (val & 0xff); + dev_dbg(&adap->dev, "%s(): rcv 0x%x [%d]\n", __FUNCTION__, val, + alg_data->mif.len); + + alg_data->mif.len--; + if (alg_data->mif.len == 0) { + if (alg_data->last) + /* Wait until the STOP is seen. */ + if (wait_timeout(I2C_PNX_TIMEOUT, alg_data)) + dev_err(&adap->dev, "The bus is still " + "active after timeout\n"); + + /* Disable master interrupts */ + ctl = ioread32(I2C_REG_CTL(alg_data)); + ctl &= ~(mcntrl_afie | mcntrl_naie | mcntrl_rffie | + mcntrl_drmie | mcntrl_daie); + iowrite32(ctl, I2C_REG_CTL(alg_data)); + + /* Kill timer. */ + del_timer_sync(&alg_data->mif.timer); + complete(&alg_data->mif.complete); + } + } + + dev_dbg(&adap->dev, "%s(): exiting: stat = %04x.\n", + __FUNCTION__, ioread32(I2C_REG_STS(alg_data))); + + return 0; +} + +static irqreturn_t +i2c_pnx_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + u32 stat, ctl; + struct i2c_adapter *adap = dev_id; + struct i2c_pnx_algo_data *alg_data = adap->algo_data; + + dev_dbg(&adap->dev, "%s(): mstat = %x mctrl = %x, mode = %d\n", + __FUNCTION__, + ioread32(I2C_REG_STS(alg_data)), + ioread32(I2C_REG_CTL(alg_data)), + alg_data->mif.mode); + stat = ioread32(I2C_REG_STS(alg_data)); + + /* let's see what kind of event this is */ + if (stat & mstatus_afi) { + /* We lost arbitration in the midst of a transfer */ + alg_data->mif.ret = -EIO; + + /* Disable master interrupts. */ + ctl = ioread32(I2C_REG_CTL(alg_data)); + ctl &= ~(mcntrl_afie | mcntrl_naie | mcntrl_rffie | + mcntrl_drmie); + iowrite32(ctl, I2C_REG_CTL(alg_data)); + + /* Stop timer, to prevent timeout. */ + del_timer_sync(&alg_data->mif.timer); + complete(&alg_data->mif.complete); + } else if (stat & mstatus_nai) { + /* Slave did not acknowledge, generate a STOP */ + dev_dbg(&adap->dev, "%s(): " + "Slave did not acknowledge, generating a STOP.\n", + __FUNCTION__); + i2c_pnx_stop(adap); + + /* Disable master interrupts. */ + ctl = ioread32(I2C_REG_CTL(alg_data)); + ctl &= ~(mcntrl_afie | mcntrl_naie | mcntrl_rffie | + mcntrl_drmie); + iowrite32(ctl, I2C_REG_CTL(alg_data)); + + /* Our return value. */ + alg_data->mif.ret = -EIO; + + /* Stop timer, to prevent timeout. */ + del_timer_sync(&alg_data->mif.timer); + complete(&alg_data->mif.complete); + } else { + /* + * Two options: + * - Master Tx needs data. + * - There is data in the Rx-fifo + * The latter is only the case if we have requested for data, + * via a dummy write. (See 'i2c_pnx_master_rcv'.) + * We therefore check, as a sanity check, whether that interrupt + * has been enabled. + */ + if ((stat & mstatus_drmi) || !(stat & mstatus_rfe)) { + if (alg_data->mif.mode == I2C_SMBUS_WRITE) { + i2c_pnx_master_xmit(adap); + } else if (alg_data->mif.mode == I2C_SMBUS_READ) { + i2c_pnx_master_rcv(adap); + } + } + } + + /* Clear TDI and AFI bits */ + stat = ioread32(I2C_REG_STS(alg_data)); + iowrite32(stat | mstatus_tdi | mstatus_afi, I2C_REG_STS(alg_data)); + + dev_dbg(&adap->dev, "%s(): exiting, stat = %x ctrl = %x.\n", + __FUNCTION__, ioread32(I2C_REG_STS(alg_data)), + ioread32(I2C_REG_CTL(alg_data))); + + return IRQ_HANDLED; +} + +static void i2c_pnx_timeout(unsigned long data) +{ + struct i2c_adapter *adap = (struct i2c_adapter *)data; + struct i2c_pnx_algo_data *alg_data = adap->algo_data; + u32 ctl; + + dev_err(&adap->dev, "Master timed out. stat = %04x, cntrl = %04x. " + "Resetting master...\n", + ioread32(I2C_REG_STS(alg_data)), + ioread32(I2C_REG_CTL(alg_data))); + + /* Reset master and disable interrupts */ + ctl = ioread32(I2C_REG_CTL(alg_data)); + ctl &= ~(mcntrl_afie | mcntrl_naie | mcntrl_rffie | mcntrl_drmie); + iowrite32(ctl, I2C_REG_CTL(alg_data)); + + ctl |= mcntrl_reset; + iowrite32(ctl, I2C_REG_CTL(alg_data)); + wait_reset(I2C_PNX_TIMEOUT, alg_data); + alg_data->mif.ret = -EIO; + complete(&alg_data->mif.complete); +} + +static inline void bus_reset_if_active(struct i2c_adapter *adap) +{ + struct i2c_pnx_algo_data *alg_data = adap->algo_data; + u32 stat; + + if ((stat = ioread32(I2C_REG_STS(alg_data))) & mstatus_active) { + dev_err(&adap->dev, + "%s: Bus is still active after xfer. Reset it...\n", + adap->name); + iowrite32(ioread32(I2C_REG_CTL(alg_data)) | mcntrl_reset, + I2C_REG_CTL(alg_data)); + wait_reset(I2C_PNX_TIMEOUT, alg_data); + } else if (!(stat & mstatus_rfe) || !(stat & mstatus_tfe)) { + /* If there is data in the fifo's after transfer, + * flush fifo's by reset. + */ + iowrite32(ioread32(I2C_REG_CTL(alg_data)) | mcntrl_reset, + I2C_REG_CTL(alg_data)); + wait_reset(I2C_PNX_TIMEOUT, alg_data); + } else if (stat & mstatus_nai) { + iowrite32(ioread32(I2C_REG_CTL(alg_data)) | mcntrl_reset, + I2C_REG_CTL(alg_data)); + wait_reset(I2C_PNX_TIMEOUT, alg_data); + } +} + +/** + * i2c_pnx_xfer - generic transfer entry point + * @adap: pointer to I2C adapter structure + * @msgs: array of messages + * @num: number of messages + * + * Initiates the transfer + */ +static int +i2c_pnx_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) +{ + struct i2c_msg *pmsg; + int rc = 0, completed = 0, i; + struct i2c_pnx_algo_data *alg_data = adap->algo_data; + u32 stat = ioread32(I2C_REG_STS(alg_data)); + + dev_dbg(&adap->dev, "%s(): entering: %d messages, stat = %04x.\n", + __FUNCTION__, num, ioread32(I2C_REG_STS(alg_data))); + + bus_reset_if_active(adap); + + /* Process transactions in a loop. */ + for (i = 0; rc >= 0 && i < num; i++) { + u8 addr; + + pmsg = &msgs[i]; + addr = pmsg->addr; + + if (pmsg->flags & I2C_M_TEN) { + dev_err(&adap->dev, + "%s: 10 bits addr not supported!\n", + adap->name); + rc = -EINVAL; + break; + } + + alg_data->mif.buf = pmsg->buf; + alg_data->mif.len = pmsg->len; + alg_data->mif.mode = (pmsg->flags & I2C_M_RD) ? + I2C_SMBUS_READ : I2C_SMBUS_WRITE; + alg_data->mif.ret = 0; + alg_data->last = (i == num - 1); + + dev_dbg(&adap->dev, "%s(): mode %d, %d bytes\n", __FUNCTION__, + alg_data->mif.mode, + alg_data->mif.len); + + i2c_pnx_arm_timer(adap); + + /* initialize the completion var */ + init_completion(&alg_data->mif.complete); + + /* Enable master interrupt */ + iowrite32(ioread32(I2C_REG_CTL(alg_data)) | mcntrl_afie | + mcntrl_naie | mcntrl_drmie, + I2C_REG_CTL(alg_data)); + + /* Put start-code and slave-address on the bus. */ + rc = i2c_pnx_start(addr, adap); + if (rc < 0) + break; + + /* Wait for completion */ + wait_for_completion(&alg_data->mif.complete); + + if (!(rc = alg_data->mif.ret)) + completed++; + dev_dbg(&adap->dev, "%s(): Complete, return code = %d.\n", + __FUNCTION__, rc); + + /* Clear TDI and AFI bits in case they are set. */ + if ((stat = ioread32(I2C_REG_STS(alg_data))) & mstatus_tdi) { + dev_dbg(&adap->dev, + "%s: TDI still set... clearing now.\n", + adap->name); + iowrite32(stat, I2C_REG_STS(alg_data)); + } + if ((stat = ioread32(I2C_REG_STS(alg_data))) & mstatus_afi) { + dev_dbg(&adap->dev, + "%s: AFI still set... clearing now.\n", + adap->name); + iowrite32(stat, I2C_REG_STS(alg_data)); + } + } + + bus_reset_if_active(adap); + + /* Cleanup to be sure... */ + alg_data->mif.buf = NULL; + alg_data->mif.len = 0; + + dev_dbg(&adap->dev, "%s(): exiting, stat = %x\n", + __FUNCTION__, ioread32(I2C_REG_STS(alg_data))); + + if (completed != num) + return ((rc < 0) ? rc : -EREMOTEIO); + + return num; +} + +static u32 i2c_pnx_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + +static struct i2c_algorithm pnx_algorithm = { + .master_xfer = i2c_pnx_xfer, + .functionality = i2c_pnx_func, +}; + +static int i2c_pnx_controller_suspend(struct platform_device *pdev, + pm_message_t state) +{ + struct i2c_pnx_data *i2c_pnx = platform_get_drvdata(pdev); + return i2c_pnx->suspend(pdev, state); +} + +static int i2c_pnx_controller_resume(struct platform_device *pdev) +{ + struct i2c_pnx_data *i2c_pnx = platform_get_drvdata(pdev); + return i2c_pnx->resume(pdev); +} + +static int __devinit i2c_pnx_probe(struct platform_device *pdev) +{ + unsigned long tmp; + int ret = 0; + struct i2c_pnx_algo_data *alg_data; + int freq_mhz; + struct i2c_pnx_data *i2c_pnx = pdev->dev.platform_data; + + if (!i2c_pnx || !i2c_pnx->adapter) { + dev_err(&pdev->dev, "%s: no platform data supplied\n", + __FUNCTION__); + ret = -EINVAL; + goto out; + } + + platform_set_drvdata(pdev, i2c_pnx); + + if (i2c_pnx->calculate_input_freq) + freq_mhz = i2c_pnx->calculate_input_freq(pdev); + else { + freq_mhz = PNX_DEFAULT_FREQ; + dev_info(&pdev->dev, "Setting bus frequency to default value: " + "%d MHz", freq_mhz); + } + + i2c_pnx->adapter->algo = &pnx_algorithm; + + alg_data = i2c_pnx->adapter->algo_data; + init_timer(&alg_data->mif.timer); + alg_data->mif.timer.function = i2c_pnx_timeout; + alg_data->mif.timer.data = (unsigned long)i2c_pnx->adapter; + + /* Register I/O resource */ + if (!request_region(alg_data->base, I2C_PNX_REGION_SIZE, pdev->name)) { + dev_err(&pdev->dev, + "I/O region 0x%08x for I2C already in use.\n", + alg_data->base); + ret = -ENODEV; + goto out_drvdata; + } + + if (!(alg_data->ioaddr = + (u32)ioremap(alg_data->base, I2C_PNX_REGION_SIZE))) { + dev_err(&pdev->dev, "Couldn't ioremap I2C I/O region\n"); + ret = -ENOMEM; + goto out_release; + } + + i2c_pnx->set_clock_run(pdev); + + /* + * Clock Divisor High This value is the number of system clocks + * the serial clock (SCL) will be high. + * For example, if the system clock period is 50 ns and the maximum + * desired serial period is 10000 ns (100 kHz), then CLKHI would be + * set to 0.5*(f_sys/f_i2c)-2=0.5*(20e6/100e3)-2=98. The actual value + * programmed into CLKHI will vary from this slightly due to + * variations in the output pad's rise and fall times as well as + * the deglitching filter length. + */ + + tmp = ((freq_mhz * 1000) / I2C_PNX_SPEED_KHZ) / 2 - 2; + iowrite32(tmp, I2C_REG_CKH(alg_data)); + iowrite32(tmp, I2C_REG_CKL(alg_data)); + + iowrite32(mcntrl_reset, I2C_REG_CTL(alg_data)); + if (wait_reset(I2C_PNX_TIMEOUT, alg_data)) { + ret = -ENODEV; + goto out_unmap; + } + init_completion(&alg_data->mif.complete); + + ret = request_irq(alg_data->irq, i2c_pnx_interrupt, + 0, pdev->name, i2c_pnx->adapter); + if (ret) + goto out_clock; + + /* Register this adapter with the I2C subsystem */ + i2c_pnx->adapter->dev.parent = &pdev->dev; + ret = i2c_add_adapter(i2c_pnx->adapter); + if (ret < 0) { + dev_err(&pdev->dev, "I2C: Failed to add bus\n"); + goto out_irq; + } + + dev_dbg(&pdev->dev, "%s: Master at %#8x, irq %d.\n", + i2c_pnx->adapter->name, alg_data->base, alg_data->irq); + + return 0; + +out_irq: + free_irq(alg_data->irq, alg_data); +out_clock: + i2c_pnx->set_clock_stop(pdev); +out_unmap: + iounmap((void *)alg_data->ioaddr); +out_release: + release_region(alg_data->base, I2C_PNX_REGION_SIZE); +out_drvdata: + platform_set_drvdata(pdev, NULL); +out: + return ret; +} + +static int __devexit i2c_pnx_remove(struct platform_device *pdev) +{ + struct i2c_pnx_data *i2c_pnx = platform_get_drvdata(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); + i2c_del_adapter(adap); + i2c_pnx->set_clock_stop(pdev); + iounmap((void *)alg_data->ioaddr); + release_region(alg_data->base, I2C_PNX_REGION_SIZE); + platform_set_drvdata(pdev, NULL); + + return 0; +} + +static struct platform_driver i2c_pnx_driver = { + .driver = { + .name = "pnx-i2c", + .owner = THIS_MODULE, + }, + .probe = i2c_pnx_probe, + .remove = __devexit_p(i2c_pnx_remove), + .suspend = i2c_pnx_controller_suspend, + .resume = i2c_pnx_controller_resume, +}; + +static int __init i2c_adap_pnx_init(void) +{ + return platform_driver_register(&i2c_pnx_driver); +} + +static void __exit i2c_adap_pnx_exit(void) +{ + platform_driver_unregister(&i2c_pnx_driver); +} + +MODULE_AUTHOR("Vitaly Wool, Dennis Kovalev "); +MODULE_DESCRIPTION("I2C driver for Philips IP3204-based I2C busses"); +MODULE_LICENSE("GPL"); + +#ifdef CONFIG_I2C_PNX_EARLY +/* We need to make sure I2C is initialized before USB */ +subsys_initcall(i2c_adap_pnx_init); +#else +mudule_init(i2c_adap_pnx_init); +#endif +module_exit(i2c_adap_pnx_exit); -- cgit v1.2.3 From 31c095b09ea2fe6a4c752fccaabd9025e1c6e7c7 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Maneyrol Date: Sun, 10 Dec 2006 21:21:29 +0100 Subject: i2c: Add request/release_mem_region to i2c-ibm_iic bus driver Reserving I/O memory for a driver with request_mem_region is necessary to avoid memory access conflicts. Even if it's never going to happen, it is cleaner and it allows to monitor I/O memory used in /proc/iomem. Signed-off-by: Jean-Baptiste Maneyrol Signed-off-by: Jean Delvare --- drivers/i2c/busses/i2c-ibm_iic.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers/i2c/busses') diff --git a/drivers/i2c/busses/i2c-ibm_iic.c b/drivers/i2c/busses/i2c-ibm_iic.c index 781a99c1647..1898e998702 100644 --- a/drivers/i2c/busses/i2c-ibm_iic.c +++ b/drivers/i2c/busses/i2c-ibm_iic.c @@ -680,6 +680,12 @@ 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; + goto fail1; + } + if (!(dev->vaddr = ioremap(ocp->def->paddr, sizeof(struct iic_regs)))){ printk(KERN_CRIT "ibm-iic%d: failed to ioremap device registers\n", dev->idx); @@ -750,6 +756,8 @@ fail: iounmap(dev->vaddr); fail2: + release_mem_region(ocp->def->paddr, sizeof(struct iic_regs)); +fail1: ocp_set_drvdata(ocp, NULL); kfree(dev); return ret; @@ -777,6 +785,7 @@ static void __devexit iic_remove(struct ocp_device *ocp) free_irq(dev->irq, dev); } iounmap(dev->vaddr); + release_mem_region(ocp->def->paddr, sizeof(struct iic_regs)); kfree(dev); } } -- cgit v1.2.3 From ad04d5c3879dcf79ba0fa1826eab991f7b7a2de8 Mon Sep 17 00:00:00 2001 From: Hans-Frieder Vogt Date: Sun, 10 Dec 2006 21:21:29 +0100 Subject: i2c: Cleanups to the i2c-nforce2 bus driver Summary of changes: - fixes: o legacy I/O region size is 64 bytes, not 8 bytes - general cleanup: o removed code for the unsupported I2C block data, block data, proc call and block proc call transfer modes o removed detail warnings about unsupported modes that are covered in a general warning (unsupported transaction...) anyway o removed necessity of a definition of struct i2c_adapter o moved definition of struct i2c_algorithm, making forward declarations of nforce2_access and nforce2_func unnecessary - minor changes: o in the description mention the nForce 5xx chipsets o changes my e-mail address in MODULE_AUTHOR Theses cleanups shrink the driver binary size from 4.0 kB to 2.7 kB on i386. Signed-off-by: Hans-Frieder Vogt Signed-off-by: Jean Delvare --- drivers/i2c/busses/i2c-nforce2.c | 89 +++++++--------------------------------- 1 file changed, 14 insertions(+), 75 deletions(-) (limited to 'drivers/i2c/busses') diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c index e0292e414ab..ad37c10e7fe 100644 --- a/drivers/i2c/busses/i2c-nforce2.c +++ b/drivers/i2c/busses/i2c-nforce2.c @@ -35,7 +35,7 @@ nForce4 MCP55 0368 This driver supports the 2 SMBuses that are included in the MCP of the - nForce2/3/4 chipsets. + nForce2/3/4/5xx chipsets. */ /* Note: we assume there can only be one nForce2, with two SMBus interfaces */ @@ -52,8 +52,8 @@ #include MODULE_LICENSE("GPL"); -MODULE_AUTHOR ("Hans-Frieder Vogt "); -MODULE_DESCRIPTION("nForce2 SMBus driver"); +MODULE_AUTHOR ("Hans-Frieder Vogt "); +MODULE_DESCRIPTION("nForce2/3/4/5xx SMBus driver"); struct nforce2_smbus { @@ -80,9 +80,6 @@ struct nforce2_smbus { #define NVIDIA_SMB_ADDR (smbus->base + 0x02) /* address */ #define NVIDIA_SMB_CMD (smbus->base + 0x03) /* command */ #define NVIDIA_SMB_DATA (smbus->base + 0x04) /* 32 data registers */ -#define NVIDIA_SMB_BCNT (smbus->base + 0x24) /* number of data bytes */ -#define NVIDIA_SMB_ALRM_A (smbus->base + 0x25) /* alarm address */ -#define NVIDIA_SMB_ALRM_D (smbus->base + 0x26) /* 2 bytes alarm data */ #define NVIDIA_SMB_STS_DONE 0x80 #define NVIDIA_SMB_STS_ALRM 0x40 @@ -95,40 +92,17 @@ struct nforce2_smbus { #define NVIDIA_SMB_PRTCL_BYTE 0x04 #define NVIDIA_SMB_PRTCL_BYTE_DATA 0x06 #define NVIDIA_SMB_PRTCL_WORD_DATA 0x08 -#define NVIDIA_SMB_PRTCL_BLOCK_DATA 0x0a -#define NVIDIA_SMB_PRTCL_PROC_CALL 0x0c -#define NVIDIA_SMB_PRTCL_BLOCK_PROC_CALL 0x0d -#define NVIDIA_SMB_PRTCL_I2C_BLOCK_DATA 0x4a #define NVIDIA_SMB_PRTCL_PEC 0x80 static struct pci_driver nforce2_driver; -static s32 nforce2_access(struct i2c_adapter *adap, u16 addr, - unsigned short flags, char read_write, - u8 command, int size, union i2c_smbus_data *data); -static u32 nforce2_func(struct i2c_adapter *adapter); - - -static const struct i2c_algorithm smbus_algorithm = { - .smbus_xfer = nforce2_access, - .functionality = nforce2_func, -}; - -static struct i2c_adapter nforce2_adapter = { - .owner = THIS_MODULE, - .class = I2C_CLASS_HWMON, - .algo = &smbus_algorithm, -}; - -/* Return -1 on error. See smbus.h for more information */ +/* Return -1 on error */ static s32 nforce2_access(struct i2c_adapter * adap, u16 addr, unsigned short flags, char read_write, u8 command, int size, union i2c_smbus_data * data) { struct nforce2_smbus *smbus = adap->algo_data; unsigned char protocol, pec, temp; - unsigned char len = 0; /* to keep the compiler quiet */ - int i; protocol = (read_write == I2C_SMBUS_READ) ? NVIDIA_SMB_PRTCL_READ : NVIDIA_SMB_PRTCL_WRITE; @@ -163,35 +137,6 @@ static s32 nforce2_access(struct i2c_adapter * adap, u16 addr, protocol |= NVIDIA_SMB_PRTCL_WORD_DATA | pec; break; - case I2C_SMBUS_BLOCK_DATA: - outb_p(command, NVIDIA_SMB_CMD); - if (read_write == I2C_SMBUS_WRITE) { - len = min_t(u8, data->block[0], 32); - outb_p(len, NVIDIA_SMB_BCNT); - for (i = 0; i < len; i++) - outb_p(data->block[i + 1], NVIDIA_SMB_DATA+i); - } - protocol |= NVIDIA_SMB_PRTCL_BLOCK_DATA | pec; - break; - - case I2C_SMBUS_I2C_BLOCK_DATA: - len = min_t(u8, data->block[0], 32); - outb_p(command, NVIDIA_SMB_CMD); - outb_p(len, NVIDIA_SMB_BCNT); - if (read_write == I2C_SMBUS_WRITE) - for (i = 0; i < len; i++) - outb_p(data->block[i + 1], NVIDIA_SMB_DATA+i); - protocol |= NVIDIA_SMB_PRTCL_I2C_BLOCK_DATA; - break; - - case I2C_SMBUS_PROC_CALL: - dev_err(&adap->dev, "I2C_SMBUS_PROC_CALL not supported!\n"); - return -1; - - case I2C_SMBUS_BLOCK_PROC_CALL: - dev_err(&adap->dev, "I2C_SMBUS_BLOCK_PROC_CALL not supported!\n"); - return -1; - default: dev_err(&adap->dev, "Unsupported transaction %d\n", size); return -1; @@ -227,19 +172,8 @@ static s32 nforce2_access(struct i2c_adapter * adap, u16 addr, break; case I2C_SMBUS_WORD_DATA: - /* case I2C_SMBUS_PROC_CALL: not supported */ data->word = inb_p(NVIDIA_SMB_DATA) | (inb_p(NVIDIA_SMB_DATA+1) << 8); break; - - case I2C_SMBUS_BLOCK_DATA: - /* case I2C_SMBUS_BLOCK_PROC_CALL: not supported */ - len = inb_p(NVIDIA_SMB_BCNT); - len = min_t(u8, len, 32); - case I2C_SMBUS_I2C_BLOCK_DATA: - for (i = 0; i < len; i++) - data->block[i+1] = inb_p(NVIDIA_SMB_DATA + i); - data->block[0] = len; - break; } return 0; @@ -250,10 +184,14 @@ static u32 nforce2_func(struct i2c_adapter *adapter) { /* other functionality might be possible, but is not tested */ 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_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA; } +static struct i2c_algorithm smbus_algorithm = { + .smbus_xfer = nforce2_access, + .functionality = nforce2_func, +}; + static struct pci_device_id nforce2_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2_SMBUS) }, @@ -267,7 +205,6 @@ static struct pci_device_id nforce2_ids[] = { { 0 } }; - MODULE_DEVICE_TABLE (pci, nforce2_ids); @@ -291,7 +228,7 @@ static int __devinit nforce2_probe_smb (struct pci_dev *dev, int bar, } smbus->base = iobase & PCI_BASE_ADDRESS_IO_MASK; - smbus->size = 8; + smbus->size = 64; } smbus->dev = dev; @@ -300,7 +237,9 @@ static int __devinit nforce2_probe_smb (struct pci_dev *dev, int bar, smbus->base, smbus->base+smbus->size-1, name); return -1; } - smbus->adapter = nforce2_adapter; + smbus->adapter.owner = THIS_MODULE; + smbus->adapter.class = I2C_CLASS_HWMON; + smbus->adapter.algo = &smbus_algorithm; smbus->adapter.algo_data = smbus; smbus->adapter.dev.parent = &dev->dev; snprintf(smbus->adapter.name, I2C_NAME_SIZE, -- cgit v1.2.3 From 813e30e9ab917f5493147451cfdbf6356a3dcee0 Mon Sep 17 00:00:00 2001 From: Andrew Victor Date: Sun, 10 Dec 2006 21:21:30 +0100 Subject: i2c: New Atmel AT91 bus driver Add support for the I2C (Two-wire interface) controller integrated in the Atmel AT91RM9200 processor. This driver should also be usable on the Atmel AT91SAM9261 and AT91SAM9260 processors. Signed-off-by: Andrew Victor Signed-off-by: Mark M. Hoffman Signed-off-by: Jean Delvare --- drivers/i2c/busses/Kconfig | 7 + drivers/i2c/busses/Makefile | 1 + drivers/i2c/busses/i2c-at91.c | 325 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 333 insertions(+) create mode 100644 drivers/i2c/busses/i2c-at91.c (limited to 'drivers/i2c/busses') diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 291da25e84d..ab398b70058 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -74,6 +74,13 @@ config I2C_AMD8111 This driver can also be built as a module. If so, the module will be called i2c-amd8111. +config I2C_AT91 + tristate "Atmel AT91 I2C Two-Wire interface (TWI)" + depends on I2C && ARCH_AT91 && EXPERIMENTAL + help + This supports the use of the I2C interface on Atmel AT91 + processors. + config I2C_AU1550 tristate "Au1550/Au1200 SMBus interface" depends on I2C && (SOC_AU1550 || SOC_AU1200) diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 626ac71af95..a82b6bfad04 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_I2C_ALI15X3) += i2c-ali15x3.o obj-$(CONFIG_I2C_AMD756) += i2c-amd756.o obj-$(CONFIG_I2C_AMD756_S4882) += i2c-amd756-s4882.o obj-$(CONFIG_I2C_AMD8111) += i2c-amd8111.o +obj-$(CONFIG_I2C_AT91) += i2c-at91.o obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o obj-$(CONFIG_I2C_ELEKTOR) += i2c-elektor.o obj-$(CONFIG_I2C_HYDRA) += i2c-hydra.o diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c new file mode 100644 index 00000000000..67f91bdda08 --- /dev/null +++ b/drivers/i2c/busses/i2c-at91.c @@ -0,0 +1,325 @@ +/* + i2c Support for Atmel's AT91 Two-Wire Interface (TWI) + + Copyright (C) 2004 Rick Bronson + Converted to 2.6 by Andrew Victor + + Borrowed heavily from original work by: + Copyright (C) 2000 Philip Edelbrock + + 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. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#define TWI_CLOCK 100000 /* Hz. max 400 Kbits/sec */ + + +static struct clk *twi_clk; +static void __iomem *twi_base; + +#define at91_twi_read(reg) __raw_readl(twi_base + (reg)) +#define at91_twi_write(reg, val) __raw_writel((val), twi_base + (reg)) + + +/* + * Initialize the TWI hardware registers. + */ +static void __devinit at91_twi_hwinit(void) +{ + unsigned long cdiv, ckdiv; + + at91_twi_write(AT91_TWI_IDR, 0xffffffff); /* Disable all interrupts */ + at91_twi_write(AT91_TWI_CR, AT91_TWI_SWRST); /* Reset peripheral */ + at91_twi_write(AT91_TWI_CR, AT91_TWI_MSEN); /* Set Master mode */ + + /* Calcuate clock dividers */ + cdiv = (clk_get_rate(twi_clk) / (2 * TWI_CLOCK)) - 3; + cdiv = cdiv + 1; /* round up */ + ckdiv = 0; + while (cdiv > 255) { + ckdiv++; + cdiv = cdiv >> 1; + } + + if (cpu_is_at91rm9200()) { /* AT91RM9200 Errata #22 */ + if (ckdiv > 5) { + printk(KERN_ERR "AT91 I2C: Invalid TWI_CLOCK value!\n"); + ckdiv = 5; + } + } + + at91_twi_write(AT91_TWI_CWGR, (ckdiv << 16) | (cdiv << 8) | cdiv); +} + +/* + * Poll the i2c status register until the specified bit is set. + * Returns 0 if timed out (100 msec). + */ +static short at91_poll_status(unsigned long bit) +{ + int loop_cntr = 10000; + + do { + udelay(10); + } while (!(at91_twi_read(AT91_TWI_SR) & bit) && (--loop_cntr > 0)); + + return (loop_cntr > 0); +} + +static int xfer_read(struct i2c_adapter *adap, unsigned char *buf, int length) +{ + /* Send Start */ + at91_twi_write(AT91_TWI_CR, AT91_TWI_START); + + /* Read data */ + while (length--) { + if (!length) /* need to send Stop before reading last byte */ + at91_twi_write(AT91_TWI_CR, AT91_TWI_STOP); + if (!at91_poll_status(AT91_TWI_RXRDY)) { + dev_dbg(&adap->dev, "RXRDY timeout\n"); + return -ETIMEDOUT; + } + *buf++ = (at91_twi_read(AT91_TWI_RHR) & 0xff); + } + + return 0; +} + +static int xfer_write(struct i2c_adapter *adap, unsigned char *buf, int length) +{ + /* Load first byte into transmitter */ + at91_twi_write(AT91_TWI_THR, *buf++); + + /* Send Start */ + at91_twi_write(AT91_TWI_CR, AT91_TWI_START); + + do { + if (!at91_poll_status(AT91_TWI_TXRDY)) { + dev_dbg(&adap->dev, "TXRDY timeout\n"); + return -ETIMEDOUT; + } + + length--; /* byte was transmitted */ + + if (length > 0) /* more data to send? */ + at91_twi_write(AT91_TWI_THR, *buf++); + } while (length); + + /* Send Stop */ + at91_twi_write(AT91_TWI_CR, AT91_TWI_STOP); + + return 0; +} + +/* + * Generic i2c master transfer entrypoint. + * + * Note: We do not use Atmel's feature of storing the "internal device address". + * Instead the "internal device address" has to be written using a seperate + * i2c message. + * http://lists.arm.linux.org.uk/pipermail/linux-arm-kernel/2004-September/024411.html + */ +static int at91_xfer(struct i2c_adapter *adap, struct i2c_msg *pmsg, int num) +{ + int i, ret; + + dev_dbg(&adap->dev, "at91_xfer: processing %d messages:\n", num); + + for (i = 0; i < num; i++) { + dev_dbg(&adap->dev, " #%d: %sing %d byte%s %s 0x%02x\n", i, + pmsg->flags & I2C_M_RD ? "read" : "writ", + pmsg->len, pmsg->len > 1 ? "s" : "", + pmsg->flags & I2C_M_RD ? "from" : "to", pmsg->addr); + + at91_twi_write(AT91_TWI_MMR, (pmsg->addr << 16) + | ((pmsg->flags & I2C_M_RD) ? AT91_TWI_MREAD : 0)); + + if (pmsg->len && pmsg->buf) { /* sanity check */ + if (pmsg->flags & I2C_M_RD) + ret = xfer_read(adap, pmsg->buf, pmsg->len); + else + ret = xfer_write(adap, pmsg->buf, pmsg->len); + + if (ret) + return ret; + + /* Wait until transfer is finished */ + if (!at91_poll_status(AT91_TWI_TXCOMP)) { + dev_dbg(&adap->dev, "TXCOMP timeout\n"); + return -ETIMEDOUT; + } + } + dev_dbg(&adap->dev, "transfer complete\n"); + pmsg++; /* next message */ + } + return i; +} + +/* + * Return list of supported functionality. + */ +static u32 at91_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + +static struct i2c_algorithm at91_algorithm = { + .master_xfer = at91_xfer, + .functionality = at91_func, +}; + +/* + * Main initialization routine. + */ +static int __devinit at91_i2c_probe(struct platform_device *pdev) +{ + struct i2c_adapter *adapter; + struct resource *res; + int rc; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENXIO; + + if (!request_mem_region(res->start, res->end - res->start + 1, "at91_i2c")) + return -EBUSY; + + twi_base = ioremap(res->start, res->end - res->start + 1); + if (!twi_base) { + rc = -ENOMEM; + goto fail0; + } + + twi_clk = clk_get(NULL, "twi_clk"); + if (IS_ERR(twi_clk)) { + dev_err(&pdev->dev, "no clock defined\n"); + rc = -ENODEV; + goto fail1; + } + + adapter = kzalloc(sizeof(struct i2c_adapter), GFP_KERNEL); + if (adapter == NULL) { + dev_err(&pdev->dev, "can't allocate inteface!\n"); + rc = -ENOMEM; + goto fail2; + } + sprintf(adapter->name, "AT91"); + adapter->algo = &at91_algorithm; + adapter->class = I2C_CLASS_HWMON; + adapter->dev.parent = &pdev->dev; + + platform_set_drvdata(pdev, adapter); + + clk_enable(twi_clk); /* enable peripheral clock */ + at91_twi_hwinit(); /* initialize TWI controller */ + + rc = i2c_add_adapter(adapter); + if (rc) { + dev_err(&pdev->dev, "Adapter %s registration failed\n", + adapter->name); + goto fail3; + } + + dev_info(&pdev->dev, "AT91 i2c bus driver.\n"); + return 0; + +fail3: + platform_set_drvdata(pdev, NULL); + kfree(adapter); + clk_disable(twi_clk); +fail2: + clk_put(twi_clk); +fail1: + iounmap(twi_base); +fail0: + release_mem_region(res->start, res->end - res->start + 1); + + return rc; +} + +static int __devexit at91_i2c_remove(struct platform_device *pdev) +{ + struct i2c_adapter *adapter = platform_get_drvdata(pdev); + struct resource *res; + int rc; + + rc = i2c_del_adapter(adapter); + platform_set_drvdata(pdev, NULL); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + iounmap(twi_base); + release_mem_region(res->start, res->end - res->start + 1); + + clk_disable(twi_clk); /* disable peripheral clock */ + clk_put(twi_clk); + + return rc; +} + +#ifdef CONFIG_PM + +/* NOTE: could save a few mA by keeping clock off outside of at91_xfer... */ + +static int at91_i2c_suspend(struct platform_device *pdev, pm_message_t mesg) +{ + clk_disable(twi_clk); + return 0; +} + +static int at91_i2c_resume(struct platform_device *pdev) +{ + return clk_enable(twi_clk); +} + +#else +#define at91_i2c_suspend NULL +#define at91_i2c_resume NULL +#endif + +static struct platform_driver at91_i2c_driver = { + .probe = at91_i2c_probe, + .remove = __devexit_p(at91_i2c_remove), + .suspend = at91_i2c_suspend, + .resume = at91_i2c_resume, + .driver = { + .name = "at91_i2c", + .owner = THIS_MODULE, + }, +}; + +static int __init at91_i2c_init(void) +{ + return platform_driver_register(&at91_i2c_driver); +} + +static void __exit at91_i2c_exit(void) +{ + platform_driver_unregister(&at91_i2c_driver); +} + +module_init(at91_i2c_init); +module_exit(at91_i2c_exit); + +MODULE_AUTHOR("Rick Bronson"); +MODULE_DESCRIPTION("I2C (TWI) driver for Atmel AT91"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 6b65cd742823f78a6538491982159098ab5fcae1 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 10 Dec 2006 21:21:32 +0100 Subject: i2c: New ARM Versatile/Realview bus driver Add support for the I2C bus found on the ARM Versatile and Realview platforms. The I2C bus has a RTC and optionally some EEPROMs attached. Signed-off-by: Russell King Signed-off-by: Jean Delvare --- drivers/i2c/busses/Kconfig | 11 +++ drivers/i2c/busses/Makefile | 1 + drivers/i2c/busses/i2c-versatile.c | 153 +++++++++++++++++++++++++++++++++++++ 3 files changed, 165 insertions(+) create mode 100644 drivers/i2c/busses/i2c-versatile.c (limited to 'drivers/i2c/busses') diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index ab398b70058..e1989f3a268 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -476,6 +476,17 @@ config I2C_STUB If you don't know what to do here, definitely say N. +config I2C_VERSATILE + tristate "ARM Versatile/Realview I2C bus support" + depends on I2C && (ARCH_VERSATILE || ARCH_REALVIEW) + select I2C_ALGOBIT + help + Say yes if you want to support the I2C serial bus on ARMs Versatile + range of platforms. + + This driver can also be built as a module. If so, the module + will be called i2c-versatile. + config I2C_VIA tristate "VIA 82C586B" depends on I2C && PCI && EXPERIMENTAL diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index a82b6bfad04..37196c1d079 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -40,6 +40,7 @@ obj-$(CONFIG_I2C_SIS5595) += i2c-sis5595.o obj-$(CONFIG_I2C_SIS630) += i2c-sis630.o obj-$(CONFIG_I2C_SIS96X) += i2c-sis96x.o obj-$(CONFIG_I2C_STUB) += i2c-stub.o +obj-$(CONFIG_I2C_VERSATILE) += i2c-versatile.o obj-$(CONFIG_I2C_VIA) += i2c-via.o obj-$(CONFIG_I2C_VIAPRO) += i2c-viapro.o obj-$(CONFIG_I2C_VOODOO3) += i2c-voodoo3.o diff --git a/drivers/i2c/busses/i2c-versatile.c b/drivers/i2c/busses/i2c-versatile.c new file mode 100644 index 00000000000..081d9578ce1 --- /dev/null +++ b/drivers/i2c/busses/i2c-versatile.c @@ -0,0 +1,153 @@ +/* + * i2c-versatile.c + * + * Copyright (C) 2006 ARM Ltd. + * written by Russell King, Deep Blue Solutions Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include +#include + +#include + +#define I2C_CONTROL 0x00 +#define I2C_CONTROLS 0x00 +#define I2C_CONTROLC 0x04 +#define SCL (1 << 0) +#define SDA (1 << 1) + +struct i2c_versatile { + struct i2c_adapter adap; + struct i2c_algo_bit_data algo; + void __iomem *base; +}; + +static void i2c_versatile_setsda(void *data, int state) +{ + struct i2c_versatile *i2c = data; + + writel(SDA, i2c->base + (state ? I2C_CONTROLS : I2C_CONTROLC)); +} + +static void i2c_versatile_setscl(void *data, int state) +{ + struct i2c_versatile *i2c = data; + + writel(SCL, i2c->base + (state ? I2C_CONTROLS : I2C_CONTROLC)); +} + +static int i2c_versatile_getsda(void *data) +{ + struct i2c_versatile *i2c = data; + return !!(readl(i2c->base + I2C_CONTROL) & SDA); +} + +static int i2c_versatile_getscl(void *data) +{ + struct i2c_versatile *i2c = data; + return !!(readl(i2c->base + I2C_CONTROL) & SCL); +} + +static struct i2c_algo_bit_data i2c_versatile_algo = { + .setsda = i2c_versatile_setsda, + .setscl = i2c_versatile_setscl, + .getsda = i2c_versatile_getsda, + .getscl = i2c_versatile_getscl, + .udelay = 30, + .timeout = HZ, +}; + +static int i2c_versatile_probe(struct platform_device *dev) +{ + struct i2c_versatile *i2c; + struct resource *r; + int ret; + + r = platform_get_resource(dev, IORESOURCE_MEM, 0); + if (!r) { + ret = -EINVAL; + goto err_out; + } + + if (!request_mem_region(r->start, r->end - r->start + 1, "versatile-i2c")) { + ret = -EBUSY; + goto err_out; + } + + i2c = kzalloc(sizeof(struct i2c_versatile), GFP_KERNEL); + if (!i2c) { + ret = -ENOMEM; + goto err_release; + } + + i2c->base = ioremap(r->start, r->end - r->start + 1); + if (!i2c->base) { + ret = -ENOMEM; + goto err_free; + } + + writel(SCL | SDA, i2c->base + I2C_CONTROLS); + + i2c->adap.owner = THIS_MODULE; + strlcpy(i2c->adap.name, "Versatile I2C adapter", sizeof(i2c->adap.name)); + i2c->adap.algo_data = &i2c->algo; + i2c->adap.dev.parent = &dev->dev; + i2c->algo = i2c_versatile_algo; + i2c->algo.data = i2c; + + ret = i2c_bit_add_bus(&i2c->adap); + if (ret >= 0) { + platform_set_drvdata(dev, i2c); + return 0; + } + + iounmap(i2c->base); + err_free: + kfree(i2c); + err_release: + release_mem_region(r->start, r->end - r->start + 1); + err_out: + return ret; +} + +static int i2c_versatile_remove(struct platform_device *dev) +{ + struct i2c_versatile *i2c = platform_get_drvdata(dev); + + platform_set_drvdata(dev, NULL); + + i2c_del_adapter(&i2c->adap); + return 0; +} + +static struct platform_driver i2c_versatile_driver = { + .probe = i2c_versatile_probe, + .remove = i2c_versatile_remove, + .driver = { + .name = "versatile-i2c", + .owner = THIS_MODULE, + }, +}; + +static int __init i2c_versatile_init(void) +{ + return platform_driver_register(&i2c_versatile_driver); +} + +static void __exit i2c_versatile_exit(void) +{ + platform_driver_unregister(&i2c_versatile_driver); +} + +module_init(i2c_versatile_init); +module_exit(i2c_versatile_exit); + +MODULE_DESCRIPTION("ARM Versatile I2C bus driver"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 3269711b76ba27b78862c48398b0d313ccaa99c2 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sun, 10 Dec 2006 21:21:33 +0100 Subject: i2c: Discard the i2c algo del_bus wrappers They are all only calling i2c_del_adapter, so we may as well do it directly. Signed-off-by: Jean Delvare --- drivers/i2c/busses/i2c-elektor.c | 2 +- drivers/i2c/busses/i2c-hydra.c | 2 +- drivers/i2c/busses/i2c-i810.c | 6 +++--- drivers/i2c/busses/i2c-ixp2000.c | 2 +- drivers/i2c/busses/i2c-ixp4xx.c | 2 +- drivers/i2c/busses/i2c-parport-light.c | 2 +- drivers/i2c/busses/i2c-parport.c | 2 +- drivers/i2c/busses/i2c-pca-isa.c | 2 +- drivers/i2c/busses/i2c-prosavage.c | 2 +- drivers/i2c/busses/i2c-savage4.c | 2 +- drivers/i2c/busses/i2c-via.c | 2 +- drivers/i2c/busses/i2c-voodoo3.c | 6 +++--- drivers/i2c/busses/scx200_i2c.c | 2 +- 13 files changed, 17 insertions(+), 17 deletions(-) (limited to 'drivers/i2c/busses') diff --git a/drivers/i2c/busses/i2c-elektor.c b/drivers/i2c/busses/i2c-elektor.c index a591fe685f0..83496746481 100644 --- a/drivers/i2c/busses/i2c-elektor.c +++ b/drivers/i2c/busses/i2c-elektor.c @@ -293,7 +293,7 @@ static int __init i2c_pcfisa_init(void) static void i2c_pcfisa_exit(void) { - i2c_pcf_del_bus(&pcf_isa_ops); + i2c_del_adapter(&pcf_isa_ops); if (irq > 0) { disable_irq(irq); diff --git a/drivers/i2c/busses/i2c-hydra.c b/drivers/i2c/busses/i2c-hydra.c index 457d48a0ab9..9832f773651 100644 --- a/drivers/i2c/busses/i2c-hydra.c +++ b/drivers/i2c/busses/i2c-hydra.c @@ -146,7 +146,7 @@ static int __devinit hydra_probe(struct pci_dev *dev, static void __devexit hydra_remove(struct pci_dev *dev) { pdregw(hydra_bit_data.data, 0); /* clear SCLK_OE and SDAT_OE */ - i2c_bit_del_bus(&hydra_adap); + i2c_del_adapter(&hydra_adap); iounmap(hydra_bit_data.data); release_mem_region(pci_resource_start(dev, 0)+ offsetof(struct Hydra, CachePD), 4); diff --git a/drivers/i2c/busses/i2c-i810.c b/drivers/i2c/busses/i2c-i810.c index b66fb6bb187..10c98bc88aa 100644 --- a/drivers/i2c/busses/i2c-i810.c +++ b/drivers/i2c/busses/i2c-i810.c @@ -219,14 +219,14 @@ static int __devinit i810_probe(struct pci_dev *dev, const struct pci_device_id return retval; retval = i2c_bit_add_bus(&i810_ddc_adapter); if (retval) - i2c_bit_del_bus(&i810_i2c_adapter); + i2c_del_adapter(&i810_i2c_adapter); return retval; } static void __devexit i810_remove(struct pci_dev *dev) { - i2c_bit_del_bus(&i810_ddc_adapter); - i2c_bit_del_bus(&i810_i2c_adapter); + i2c_del_adapter(&i810_ddc_adapter); + i2c_del_adapter(&i810_i2c_adapter); iounmap(ioaddr); } diff --git a/drivers/i2c/busses/i2c-ixp2000.c b/drivers/i2c/busses/i2c-ixp2000.c index dd3f4cd3aa6..efa3ecc5522 100644 --- a/drivers/i2c/busses/i2c-ixp2000.c +++ b/drivers/i2c/busses/i2c-ixp2000.c @@ -90,7 +90,7 @@ static int ixp2000_i2c_remove(struct platform_device *plat_dev) platform_set_drvdata(plat_dev, NULL); - i2c_bit_del_bus(&drv_data->adapter); + i2c_del_adapter(&drv_data->adapter); kfree(drv_data); diff --git a/drivers/i2c/busses/i2c-ixp4xx.c b/drivers/i2c/busses/i2c-ixp4xx.c index 68fe863f9d5..08e89b83984 100644 --- a/drivers/i2c/busses/i2c-ixp4xx.c +++ b/drivers/i2c/busses/i2c-ixp4xx.c @@ -91,7 +91,7 @@ static int ixp4xx_i2c_remove(struct platform_device *plat_dev) platform_set_drvdata(plat_dev, NULL); - i2c_bit_del_bus(&drv_data->adapter); + i2c_del_adapter(&drv_data->adapter); kfree(drv_data); diff --git a/drivers/i2c/busses/i2c-parport-light.c b/drivers/i2c/busses/i2c-parport-light.c index 5eb2bd294fd..4bc42810b9a 100644 --- a/drivers/i2c/busses/i2c-parport-light.c +++ b/drivers/i2c/busses/i2c-parport-light.c @@ -163,7 +163,7 @@ static void __exit i2c_parport_exit(void) if (adapter_parm[type].init.val) line_set(0, &adapter_parm[type].init); - i2c_bit_del_bus(&parport_adapter); + i2c_del_adapter(&parport_adapter); release_region(base, 3); } diff --git a/drivers/i2c/busses/i2c-parport.c b/drivers/i2c/busses/i2c-parport.c index 48a829431c7..66696a40c7b 100644 --- a/drivers/i2c/busses/i2c-parport.c +++ b/drivers/i2c/busses/i2c-parport.c @@ -218,7 +218,7 @@ static void i2c_parport_detach (struct parport *port) if (adapter_parm[type].init.val) line_set(port, 0, &adapter_parm[type].init); - i2c_bit_del_bus(&adapter->adapter); + i2c_del_adapter(&adapter->adapter); parport_unregister_device(adapter->pdev); if (prev) prev->next = adapter->next; diff --git a/drivers/i2c/busses/i2c-pca-isa.c b/drivers/i2c/busses/i2c-pca-isa.c index 407840b6a26..cc6536a19ec 100644 --- a/drivers/i2c/busses/i2c-pca-isa.c +++ b/drivers/i2c/busses/i2c-pca-isa.c @@ -156,7 +156,7 @@ static int __init pca_isa_init(void) static void pca_isa_exit(void) { - i2c_pca_del_bus(&pca_isa_ops); + i2c_del_adapter(&pca_isa_ops); if (irq > 0) { disable_irq(irq); diff --git a/drivers/i2c/busses/i2c-prosavage.c b/drivers/i2c/busses/i2c-prosavage.c index 7745e21874a..07c1f1e27df 100644 --- a/drivers/i2c/busses/i2c-prosavage.c +++ b/drivers/i2c/busses/i2c-prosavage.c @@ -212,7 +212,7 @@ static void prosavage_remove(struct pci_dev *dev) if (chip->i2c_bus[i].adap_ok == 0) continue; - ret = i2c_bit_del_bus(&chip->i2c_bus[i].adap); + ret = i2c_del_adapter(&chip->i2c_bus[i].adap); if (ret) { dev_err(&dev->dev, "%s not removed\n", chip->i2c_bus[i].adap.name); diff --git a/drivers/i2c/busses/i2c-savage4.c b/drivers/i2c/busses/i2c-savage4.c index 209f47ea175..844b4ff9089 100644 --- a/drivers/i2c/busses/i2c-savage4.c +++ b/drivers/i2c/busses/i2c-savage4.c @@ -173,7 +173,7 @@ static int __devinit savage4_probe(struct pci_dev *dev, const struct pci_device_ static void __devexit savage4_remove(struct pci_dev *dev) { - i2c_bit_del_bus(&savage4_i2c_adapter); + i2c_del_adapter(&savage4_i2c_adapter); iounmap(ioaddr); } diff --git a/drivers/i2c/busses/i2c-via.c b/drivers/i2c/busses/i2c-via.c index 910e200ad50..15d7e00e47e 100644 --- a/drivers/i2c/busses/i2c-via.c +++ b/drivers/i2c/busses/i2c-via.c @@ -151,7 +151,7 @@ static int __devinit vt586b_probe(struct pci_dev *dev, const struct pci_device_i static void __devexit vt586b_remove(struct pci_dev *dev) { - i2c_bit_del_bus(&vt586b_adapter); + i2c_del_adapter(&vt586b_adapter); release_region(I2C_DIR, IOSPACE); pm_io_base = 0; } diff --git a/drivers/i2c/busses/i2c-voodoo3.c b/drivers/i2c/busses/i2c-voodoo3.c index 6c8d2518338..b0377b81744 100644 --- a/drivers/i2c/busses/i2c-voodoo3.c +++ b/drivers/i2c/busses/i2c-voodoo3.c @@ -211,14 +211,14 @@ static int __devinit voodoo3_probe(struct pci_dev *dev, const struct pci_device_ return retval; retval = i2c_bit_add_bus(&voodoo3_ddc_adapter); if (retval) - i2c_bit_del_bus(&voodoo3_i2c_adapter); + i2c_del_adapter(&voodoo3_i2c_adapter); return retval; } static void __devexit voodoo3_remove(struct pci_dev *dev) { - i2c_bit_del_bus(&voodoo3_i2c_adapter); - i2c_bit_del_bus(&voodoo3_ddc_adapter); + i2c_del_adapter(&voodoo3_i2c_adapter); + i2c_del_adapter(&voodoo3_ddc_adapter); iounmap(ioaddr); } diff --git a/drivers/i2c/busses/scx200_i2c.c b/drivers/i2c/busses/scx200_i2c.c index 8ddbae4fafe..6cd96e43aa7 100644 --- a/drivers/i2c/busses/scx200_i2c.c +++ b/drivers/i2c/busses/scx200_i2c.c @@ -116,7 +116,7 @@ static int scx200_i2c_init(void) static void scx200_i2c_cleanup(void) { - i2c_bit_del_bus(&scx200_i2c_ops); + i2c_del_adapter(&scx200_i2c_ops); } module_init(scx200_i2c_init); -- cgit v1.2.3 From 250d1bd3f4ed0b50d79b3ec81ccefbabb203f916 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sun, 10 Dec 2006 21:21:33 +0100 Subject: i2c: Enable PEC on more i2c-i801 devices Enable PEC on recent Intel SMBus controllers (ICH6, ICH7, ICH8, ICH9 and ESB2.) Signed-off-by: Jean Delvare Acked-by: Jason Gaston --- drivers/i2c/busses/i2c-i801.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'drivers/i2c/busses') diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index c7be2fdbd86..ae625b85447 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -470,12 +470,20 @@ static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id int err; I801_dev = dev; - if ((dev->device == PCI_DEVICE_ID_INTEL_82801DB_3) || - (dev->device == PCI_DEVICE_ID_INTEL_82801EB_3) || - (dev->device == PCI_DEVICE_ID_INTEL_ESB_4)) + 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: + case PCI_DEVICE_ID_INTEL_ICH7_17: + case PCI_DEVICE_ID_INTEL_ESB2_17: + case PCI_DEVICE_ID_INTEL_ICH8_5: + case PCI_DEVICE_ID_INTEL_ICH9_6: isich4 = 1; - else + break; + default: isich4 = 0; + } err = pci_enable_device(dev); if (err) { -- cgit v1.2.3 From d7aef138f3c08c5bbab567bc9a84e43a88f50395 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sun, 10 Dec 2006 21:21:34 +0100 Subject: i2c: Fix OMAP clock prescaler to match the comment Signed-off-by: Jean Delvare Signed-off-by: Tony Lindgren --- drivers/i2c/busses/i2c-omap.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/i2c/busses') diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index dec04da0455..bcd8367cede 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -231,8 +231,8 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) * 13 2 1 * 19.2 2 1 */ - if (fclk_rate > 16000000) - psc = (fclk_rate + 8000000) / 12000000; + if (fclk_rate > 12000000) + psc = fclk_rate / 12000000; } /* Setup clock prescaler to obtain approx 12MHz I2C module clock: */ -- cgit v1.2.3 From 7188cc66b4facf749e4fc0a44165b06716e1b621 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Tue, 12 Dec 2006 18:18:30 +0100 Subject: hwmon: Update Rudolf Marek's e-mail address The Silicon Hill club is not what it used to be. Signed-off-by: Rudolf Marek Signed-off-by: Jean Delvare --- drivers/i2c/busses/i2c-ali1563.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/i2c/busses') diff --git a/drivers/i2c/busses/i2c-ali1563.c b/drivers/i2c/busses/i2c-ali1563.c index 33fbb47100a..8e1e3f8e40a 100644 --- a/drivers/i2c/busses/i2c-ali1563.c +++ b/drivers/i2c/busses/i2c-ali1563.c @@ -2,7 +2,7 @@ * i2c-ali1563.c - i2c driver for the ALi 1563 Southbridge * * Copyright (C) 2004 Patrick Mochel - * 2005 Rudolf Marek + * 2005 Rudolf Marek * * The 1563 southbridge is deceptively similar to the 1533, with a * few notable exceptions. One of those happens to be the fact they -- cgit v1.2.3 From 6c566fb7b3cda741dd6ed60c7d6aae0e17c9c8fe Mon Sep 17 00:00:00 2001 From: Vitaly Wool Date: Thu, 4 Jan 2007 13:07:03 +0100 Subject: i2c-pnx: Fix interrupt handler, get rid of EARLY config option This fixes two issues raised by David Brownell on the i2c list: << Someone needs to update i2c-pnx.c to handle the IRQ handler doesn't expect pt_regs (gone now for a while), and so it doesn't try to reference "mudule_init()" if I2C isn't initialized "early". For that matter, to get rid of that _option_ to initialize then, and always init that driver with subsystem_init() ... it's common with embedded systems to need I2C access to tweak a GPIO expander or do some other work when bringing up drivers, that's not specific to USB stacks. >> Signed-off-by: Vitaly Wool Signed-off-by: Jean Delvare --- drivers/i2c/busses/Kconfig | 9 --------- drivers/i2c/busses/i2c-pnx.c | 7 +------ 2 files changed, 1 insertion(+), 15 deletions(-) (limited to 'drivers/i2c/busses') diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index e1989f3a268..9367c4cfe93 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -564,13 +564,4 @@ config I2C_PNX This driver can also be built as a module. If so, the module will be called i2c-pnx. -config I2C_PNX_EARLY - bool "Early initialization for I2C on PNXxxxx" - depends on I2C_PNX=y - help - Under certain circumstances one may need to make sure I2C on PNXxxxx - is initialized earlier than some other driver that depends on it - (for instance, that might be USB in case of PNX4008). With this - option turned on you can guarantee that. - endmenu diff --git a/drivers/i2c/busses/i2c-pnx.c b/drivers/i2c/busses/i2c-pnx.c index de0bca77e92..17376feb1ac 100644 --- a/drivers/i2c/busses/i2c-pnx.c +++ b/drivers/i2c/busses/i2c-pnx.c @@ -305,8 +305,7 @@ static int i2c_pnx_master_rcv(struct i2c_adapter *adap) return 0; } -static irqreturn_t -i2c_pnx_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t i2c_pnx_interrupt(int irq, void *dev_id) { u32 stat, ctl; struct i2c_adapter *adap = dev_id; @@ -699,10 +698,6 @@ MODULE_AUTHOR("Vitaly Wool, Dennis Kovalev "); MODULE_DESCRIPTION("I2C driver for Philips IP3204-based I2C busses"); MODULE_LICENSE("GPL"); -#ifdef CONFIG_I2C_PNX_EARLY /* We need to make sure I2C is initialized before USB */ subsys_initcall(i2c_adap_pnx_init); -#else -mudule_init(i2c_adap_pnx_init); -#endif module_exit(i2c_adap_pnx_exit); -- cgit v1.2.3 From 3269bb63eb076318ce4fb554851d047e1c9aa1a5 Mon Sep 17 00:00:00 2001 From: Maxime Bizon Date: Fri, 5 Jan 2007 17:54:05 +0100 Subject: i2c-mv64xxx: Fix random oops at boot I have a Marvell board which has the same i2c hw block than mv64xxx, so I'm trying to use i2c-mv64xxx driver. But I get the following random oops at boot: Unable to handle kernel NULL pointer dereference at virtual address 00000002 Backtrace: [] (mv64xxx_i2c_intr+0x0/0x2b8) from [] (__do_irq+0x4c/0x8c) [] (__do_irq+0x0/0x8c) from [] (do_level_IRQ+0x68/0xc0) r8 = C0501E08 r7 = 00000005 r6 = C0501E08 r5 = 00000005 r4 = C048BB78 [] (do_level_IRQ+0x0/0xc0) from [] (asm_do_IRQ+0x50/0x134) r6 = C0449C78 r5 = F1020000 r4 = FFFFFFFF [] (asm_do_IRQ+0x0/0x134) from [] (__irq_svc+0x24/0x100) r8 = C1CAC400 r7 = 00000005 r6 = 00000002 r5 = F1020000 r4 = FFFFFFFF [] (setup_irq+0x0/0x124) from [] (request_irq+0xb0/0xd0) r7 = C041B2AC r6 = C0397E4C r5 = 00000000 r4 = 00000005 [] (request_irq+0x0/0xd0) from [] (mv64xxx_i2c_probe+0x148/0x244) [] (mv64xxx_i2c_probe+0x0/0x244) from [] (platform_drv_probe+0x20/0x24) The oops is caused by a spurious interrupt that occurs when request_irq is called. mv64xxx_i2c_fsm() tries to read drv_data->msg, which is NULL. I noticed that hardware init is done after requesting irq. Thus any pending irq from previous hardware usage may cause this. The following patch fixes it: Signed-off-by: Maxime Bizon Acked-by: Mark A. Greer Signed-off-by: Jean Delvare --- drivers/i2c/busses/i2c-mv64xxx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/i2c/busses') diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c index bbc8e3a7ff5..490173611d6 100644 --- a/drivers/i2c/busses/i2c-mv64xxx.c +++ b/drivers/i2c/busses/i2c-mv64xxx.c @@ -529,6 +529,8 @@ mv64xxx_i2c_probe(struct platform_device *pd) platform_set_drvdata(pd, drv_data); i2c_set_adapdata(&drv_data->adapter, drv_data); + mv64xxx_i2c_hw_init(drv_data); + if (request_irq(drv_data->irq, mv64xxx_i2c_intr, 0, MV64XXX_I2C_CTLR_NAME, drv_data)) { dev_err(&drv_data->adapter.dev, @@ -542,8 +544,6 @@ mv64xxx_i2c_probe(struct platform_device *pd) goto exit_free_irq; } - mv64xxx_i2c_hw_init(drv_data); - return 0; exit_free_irq: -- cgit v1.2.3