This support is also available as a module. If so, the module
will be called i2c-algo-pcf.
-config I2C_KEYWEST
- tristate "Powermac Keywest I2C interface"
- depends on I2C && PPC_PMAC
- help
- This supports the use of the I2C interface in the combo-I/O
- chip on recent Apple machines. Say Y if you have such a machine.
-
- This support is also available as a module. If so, the module
- will be called i2c-keywest.
-
-config ITE_I2C_ALGO
+config I2C_ALGOITE
tristate "ITE I2C Algorithm"
depends on MIPS_ITE8172 && I2C
help
This support is also available as a module. If so, the module
will be called i2c-algo-ite.
-config ITE_I2C_ADAP
- tristate "ITE I2C Adapter"
- depends on ITE_I2C_ALGO
- 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-adap-ite.
-
config I2C_ALGO8XX
tristate "MPC8xx CPM I2C interface"
depends on 8xx && I2C
-config I2C_RPXLITE
- tristate "Embedded Planet RPX Lite/Classic suppoort"
- depends on (RPXLITE || RPXCLASSIC) && I2C_ALGO8XX
-
-config I2C_IBM_IIC
- tristate "IBM IIC I2C"
- depends on IBM_OCP && I2C
-
-config I2C_IOP3XX
- tristate "Intel XScale IOP3xx on-chip I2C interface"
- depends on ARCH_IOP3XX && I2C
-
source drivers/i2c/busses/Kconfig
source drivers/i2c/chips/Kconfig
#
-# Makefile for the kernel i2c bus driver.
+# Makefile for the i2c core.
#
obj-$(CONFIG_I2C) += i2c-core.o
obj-$(CONFIG_I2C_CHARDEV) += i2c-dev.o
+obj-$(CONFIG_I2C_SENSOR) += i2c-sensor.o
obj-$(CONFIG_I2C_ALGOBIT) += i2c-algo-bit.o
obj-$(CONFIG_I2C_ALGOPCF) += i2c-algo-pcf.o
-obj-$(CONFIG_I2C_KEYWEST) += i2c-keywest.o
-obj-$(CONFIG_ITE_I2C_ALGO) += i2c-algo-ite.o
-obj-$(CONFIG_ITE_I2C_ADAP) += i2c-adap-ite.o
-obj-$(CONFIG_I2C_IBM_IIC) += i2c-ibm_iic.o
-obj-$(CONFIG_I2C_SENSOR) += i2c-sensor.o
-obj-$(CONFIG_I2C_IOP3XX) += i2c-iop3xx.o
+obj-$(CONFIG_I2C_ALGOITE) += i2c-algo-ite.o
obj-y += busses/ chips/
# Sensor device configuration
#
-menu "I2C Hardware Sensors Mainboard support"
+menu "I2C Hardware Bus support"
config I2C_ALI1535
tristate "ALI 1535"
This driver can also be built as a module. If so, the module
will be called i2c-i810.
+config I2C_IBM_IIC
+ tristate "IBM IIC I2C"
+ depends on IBM_OCP && I2C
+
+config I2C_IOP3XX
+ tristate "Intel XScale IOP3xx on-chip I2C interface"
+ depends on ARCH_IOP3XX && I2C
+
config I2C_ISA
tristate "ISA Bus support"
depends on I2C && ISA && EXPERIMENTAL
This driver can also be built as a module. If so, the module
will be called i2c-isa.
+config I2C_ITE
+ tristate "ITE I2C Adapter"
+ depends on 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_KEYWEST
+ tristate "Powermac Keywest I2C interface"
+ depends on I2C && PPC_PMAC
+ help
+ This supports the use of the I2C interface in the combo-I/O
+ chip on recent Apple machines. Say Y if you have such a machine.
+
+ This support is also available as a module. If so, the module
+ will be called i2c-keywest.
+
config I2C_NFORCE2
tristate "Nvidia Nforce2"
depends on I2C && PCI && EXPERIMENTAL
This support is also available as a module. If so, the module
will be called i2c-prosavage.
+config I2C_RPXLITE
+ tristate "Embedded Planet RPX Lite/Classic suppoort"
+ depends on (RPXLITE || RPXCLASSIC) && I2C_ALGO8XX
+
config I2C_SAVAGE4
tristate "S3 Savage 4"
depends on I2C_ALGOBIT && PCI && EXPERIMENTAL
#
-# Makefile for the kernel hardware sensors bus drivers.
+# Makefile for the i2c bus drivers.
#
obj-$(CONFIG_I2C_ALI1535) += i2c-ali1535.o
obj-$(CONFIG_I2C_ELV) += i2c-elv.o
obj-$(CONFIG_I2C_I801) += i2c-i801.o
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_KEYWEST) += i2c-keywest.o
obj-$(CONFIG_I2C_NFORCE2) += i2c-nforce2.o
obj-$(CONFIG_I2C_PHILIPSPAR) += i2c-philips-par.o
obj-$(CONFIG_I2C_PIIX4) += i2c-piix4.o
obj-$(CONFIG_I2C_PROSAVAGE) += i2c-prosavage.o
+obj-$(CONFIG_I2C_RPXLITE) += i2c-rpx.o
obj-$(CONFIG_I2C_SAVAGE4) += i2c-savage4.o
obj-$(CONFIG_I2C_SIS5595) += i2c-sis5595.o
obj-$(CONFIG_I2C_SIS630) += i2c-sis630.o
obj-$(CONFIG_I2C_VIA) += i2c-via.o
obj-$(CONFIG_I2C_VIAPRO) += i2c-viapro.o
obj-$(CONFIG_I2C_VOODOO3) += i2c-voodoo3.o
-obj-$(CONFIG_SCx200_I2C) += scx200_i2c.o
obj-$(CONFIG_SCx200_ACB) += scx200_acb.o
+obj-$(CONFIG_SCx200_I2C) += scx200_i2c.o
--- /dev/null
+
+/*
+ * linux/drivers/i2c/i2c-frodo.c
+ *
+ * Author: Abraham van der Merwe <abraham@2d3d.co.za>
+ *
+ * An I2C adapter driver for the 2d3D, Inc. StrongARM SA-1110
+ * Development board (Frodo).
+ *
+ * This source code 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 <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <asm/hardware.h>
+
+
+static void frodo_setsda (void *data,int state)
+{
+ if (state)
+ FRODO_CPLD_I2C |= FRODO_I2C_SDA_OUT;
+ else
+ FRODO_CPLD_I2C &= ~FRODO_I2C_SDA_OUT;
+}
+
+static void frodo_setscl (void *data,int state)
+{
+ if (state)
+ FRODO_CPLD_I2C |= FRODO_I2C_SCL_OUT;
+ else
+ FRODO_CPLD_I2C &= ~FRODO_I2C_SCL_OUT;
+}
+
+static int frodo_getsda (void *data)
+{
+ return ((FRODO_CPLD_I2C & FRODO_I2C_SDA_IN) != 0);
+}
+
+static int frodo_getscl (void *data)
+{
+ return ((FRODO_CPLD_I2C & FRODO_I2C_SCL_IN) != 0);
+}
+
+static struct i2c_algo_bit_data bit_frodo_data = {
+ .setsda = frodo_setsda,
+ .setscl = frodo_setscl,
+ .getsda = frodo_getsda,
+ .getscl = frodo_getscl,
+ .udelay = 80,
+ .mdelay = 80,
+ .timeout = HZ
+};
+
+static struct i2c_adapter frodo_ops = {
+ .owner = THIS_MODULE,
+ .id = I2C_HW_B_FRODO,
+ .algo_data = &bit_frodo_data,
+ .dev = {
+ .name = "Frodo adapter driver",
+ },
+};
+
+static int __init i2c_frodo_init (void)
+{
+ return i2c_bit_add_bus(&frodo_ops);
+}
+
+static void __exit i2c_frodo_exit (void)
+{
+ i2c_bit_del_bus(&frodo_ops);
+}
+
+MODULE_AUTHOR ("Abraham van der Merwe <abraham@2d3d.co.za>");
+MODULE_DESCRIPTION ("I2C-Bus adapter routines for Frodo");
+MODULE_LICENSE ("GPL");
+
+module_init (i2c_frodo_init);
+module_exit (i2c_frodo_exit);
+
--- /dev/null
+/*
+ * drivers/i2c/i2c-ibm_iic.c
+ *
+ * Support for the IIC peripheral on IBM PPC 4xx
+ *
+ * Copyright (c) 2003 Zultys Technologies.
+ * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
+ *
+ * Based on original work by
+ * Ian DaSilva <idasilva@mvista.com>
+ * Armin Kuster <akuster@mvista.com>
+ * Matt Porter <mporter@mvista.com>
+ *
+ * Copyright 2000-2003 MontaVista Software Inc.
+ *
+ * Original driver version was highly leveraged from i2c-elektor.c
+ *
+ * Copyright 1995-97 Simon G. Vogl
+ * 1998-99 Hans Berglund
+ *
+ * With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi>
+ * and even Frodo Looijaard <frodol@dds.nl>
+ *
+ * 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 <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <linux/i2c.h>
+#include <linux/i2c-id.h>
+#include <asm/ocp.h>
+#include <asm/ibm4xx.h>
+
+#include "i2c-ibm_iic.h"
+
+#define DRIVER_VERSION "2.0"
+
+MODULE_DESCRIPTION("IBM IIC driver v" DRIVER_VERSION);
+MODULE_LICENSE("GPL");
+
+static int iic_scan = 0;
+MODULE_PARM(iic_scan, "i");
+MODULE_PARM_DESC(iic_scan, "Scan for active chips on the bus");
+
+static int iic_force_poll = 0;
+MODULE_PARM(iic_force_poll, "i");
+MODULE_PARM_DESC(iic_force_poll, "Force polling mode");
+
+static int iic_force_fast = 0;
+MODULE_PARM(iic_force_fast, "i");
+MODULE_PARM_DESC(iic_fast_poll, "Force fast mode (400 kHz)");
+
+#define DBG_LEVEL 0
+
+#ifdef DBG
+#undef DBG
+#endif
+
+#ifdef DBG2
+#undef DBG2
+#endif
+
+#if DBG_LEVEL > 0
+# define DBG(x...) printk(KERN_DEBUG "ibm-iic" ##x)
+#else
+# define DBG(x...) ((void)0)
+#endif
+#if DBG_LEVEL > 1
+# define DBG2(x...) DBG( ##x )
+#else
+# define DBG2(x...) ((void)0)
+#endif
+#if DBG_LEVEL > 2
+static void dump_iic_regs(const char* header, struct ibm_iic_private* dev)
+{
+ volatile struct iic_regs *iic = dev->vaddr;
+ printk(KERN_DEBUG "ibm-iic%d: %s\n", dev->idx, header);
+ printk(KERN_DEBUG " cntl = 0x%02x, mdcntl = 0x%02x\n"
+ 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->xtcntlss), in_8(&iic->directcntl));
+}
+# define DUMP_REGS(h,dev) dump_iic_regs((h),(dev))
+#else
+# define DUMP_REGS(h,dev) ((void)0)
+#endif
+
+/* Enable/disable interrupt generation */
+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.
+ */
+static void iic_dev_init(struct ibm_iic_private* dev)
+{
+ volatile struct iic_regs *iic = dev->vaddr;
+
+ DBG("%d: init\n", dev->idx);
+
+ /* Clear master address */
+ out_8(&iic->lmadr, 0);
+ out_8(&iic->hmadr, 0);
+
+ /* Clear slave address */
+ out_8(&iic->lsadr, 0);
+ out_8(&iic->hsadr, 0);
+
+ /* Clear status & extended status */
+ out_8(&iic->sts, STS_SCMP | STS_IRQA);
+ out_8(&iic->extsts, EXTSTS_IRQP | EXTSTS_IRQD | EXTSTS_LA
+ | EXTSTS_ICT | EXTSTS_XFRA);
+
+ /* Set clock divider */
+ out_8(&iic->clkdiv, dev->clckdiv);
+
+ /* Clear transfer count */
+ out_8(&iic->xfrcnt, 0);
+
+ /* Clear extended control and status */
+ out_8(&iic->xtcntlss, XTCNTLSS_SRC | XTCNTLSS_SRS | XTCNTLSS_SWC
+ | XTCNTLSS_SWS);
+
+ /* Clear control register */
+ out_8(&iic->cntl, 0);
+
+ /* Enable interrupts if possible */
+ iic_interrupt_mode(dev, dev->irq >= 0);
+
+ /* Set mode control */
+ out_8(&iic->mdcntl, MDCNTL_FMDB | MDCNTL_EINT | MDCNTL_EUBS
+ | (dev->fast_mode ? MDCNTL_FSM : 0));
+
+ DUMP_REGS("iic_init", dev);
+}
+
+/*
+ * Reset IIC interface
+ */
+static void iic_dev_reset(struct ibm_iic_private* dev)
+{
+ volatile struct iic_regs *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);
+ 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);
+
+ /* 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);
+}
+
+/*
+ * IIC interrupt handler
+ */
+static irqreturn_t iic_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct ibm_iic_private* dev = (struct ibm_iic_private*)dev_id;
+ volatile struct iic_regs* iic = dev->vaddr;
+
+ 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;
+}
+
+/*
+ * Get master transfer result and clear errors if any.
+ * Returns the number of actually transferred bytes or error (<0)
+ */
+static int iic_xfer_result(struct ibm_iic_private* dev)
+{
+ volatile struct iic_regs *iic = dev->vaddr;
+
+ if (unlikely(in_8(&iic->sts) & STS_ERR)){
+ 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 |
+ 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
+ * state, the only way out - soft reset.
+ */
+ if ((in_8(&iic->extsts) & EXTSTS_BCS_MASK) != EXTSTS_BCS_FREE){
+ DBG("%d: bus is stuck, resetting\n", dev->idx);
+ iic_dev_reset(dev);
+ }
+ return -EREMOTEIO;
+ }
+ else
+ return in_8(&iic->xfrcnt) & XFRCNT_MTC_MASK;
+}
+
+/*
+ * Try to abort active transfer.
+ */
+static void iic_abort_xfer(struct ibm_iic_private* dev)
+{
+ volatile struct iic_regs *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)
+ */
+ x = jiffies + 2;
+ while ((in_8(&iic->extsts) & EXTSTS_BCS_MASK) != EXTSTS_BCS_FREE){
+ if (time_after(jiffies, x)){
+ DBG("%d: abort timeout, resetting...\n", dev->idx);
+ iic_dev_reset(dev);
+ return;
+ }
+ schedule();
+ }
+
+ /* Just to clear errors */
+ iic_xfer_result(dev);
+}
+
+/*
+ * Wait for master transfer to complete.
+ * It puts current process to sleep until we get interrupt or timeout expires.
+ * Returns the number of transferred bytes or error (<0)
+ */
+static int iic_wait_for_tc(struct ibm_iic_private* dev){
+
+ volatile struct iic_regs *iic = dev->vaddr;
+ int ret = 0;
+
+ if (dev->irq >= 0){
+ /* Interrupt mode */
+ wait_queue_t wait;
+ init_waitqueue_entry(&wait, current);
+
+ add_wait_queue(&dev->wq, &wait);
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (in_8(&iic->sts) & STS_PT)
+ schedule_timeout(dev->adap.timeout * HZ);
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&dev->wq, &wait);
+
+ if (unlikely(signal_pending(current))){
+ DBG("%d: wait interrupted\n", dev->idx);
+ ret = -ERESTARTSYS;
+ } else if (unlikely(in_8(&iic->sts) & STS_PT)){
+ DBG("%d: wait timeout\n", dev->idx);
+ ret = -ETIMEDOUT;
+ }
+ }
+ 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,
+ int combined_xfer)
+{
+ volatile struct iic_regs *iic = dev->vaddr;
+ char* buf = pm->buf;
+ int i, j, loops, ret = 0;
+ int len = pm->len;
+
+ 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((volatile u8*)&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",
+ 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;
+ }
+
+ if (cntl & CNTL_RW)
+ for (j = 0; j < count; ++j)
+ *buf++ = in_8((volatile u8*)&iic->mdbuf);
+ }
+
+ return ret > 0 ? 0 : ret;
+}
+
+/*
+ * Set target slave address for master transfer
+ */
+static inline void iic_address(struct ibm_iic_private* dev, struct i2c_msg* msg)
+{
+ volatile struct iic_regs *iic = dev->vaddr;
+ u16 addr = msg->addr;
+
+ 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);
+ out_8(&iic->hmadr, 0xf0 | ((addr >> 7) & 0x06));
+ }
+ else {
+ out_8(&iic->cntl, 0);
+ out_8(&iic->lmadr, addr << 1);
+ }
+}
+
+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,
+ const struct i2c_msg* p2)
+{
+ return (p1->addr != p2->addr)
+ || ((p1->flags & I2C_M_TEN) != (p2->flags & I2C_M_TEN));
+}
+
+/*
+ * 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)
+{
+ struct ibm_iic_private* dev = (struct ibm_iic_private*)(i2c_get_adapdata(adap));
+ volatile struct iic_regs *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,
+ 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)){
+ DBG("%d: invalid len %d in msg[%d]\n", dev->idx,
+ msgs[i].len, i);
+ return -EINVAL;
+ }
+ if (unlikely(iic_address_neq(&msgs[0], &msgs[i]))){
+ DBG("%d: invalid addr in msg[%d]\n", dev->idx, i);
+ 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
+ * 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);
+
+ return ret < 0 ? ret : num;
+}
+
+static u32 iic_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR;
+}
+
+static struct i2c_algorithm iic_algo = {
+ .name = "IBM IIC algorithm",
+ .id = I2C_ALGO_OCP,
+ .master_xfer = iic_xfer,
+ .smbus_xfer = NULL,
+ .slave_send = NULL,
+ .slave_recv = NULL,
+ .algo_control = NULL,
+ .functionality = iic_func
+};
+
+/*
+ * Scan bus for valid 7-bit addresses (ie things that ACK on 1 byte read)
+ * We only scan range [0x08 - 0x77], all other addresses are reserved anyway
+ */
+static void __devinit iic_scan_bus(struct ibm_iic_private* dev)
+{
+ int found = 0;
+ char dummy;
+ struct i2c_msg msg = {
+ .buf = &dummy,
+ .len = sizeof(dummy),
+ .flags = I2C_M_RD
+ };
+
+ printk(KERN_INFO "ibm-iic%d: scanning bus...\n" KERN_INFO, dev->idx);
+
+ for (msg.addr = 8; msg.addr < 0x78; ++msg.addr)
+ if (iic_xfer(&dev->adap, &msg, 1) == 1){
+ ++found;
+ printk(" 0x%02x", msg.addr);
+ }
+
+ printk("%sibm-iic%d: %d device(s) detected\n",
+ found ? "\n" KERN_INFO : "", dev->idx, found);
+}
+
+/*
+ * Calculates IICx_CLCKDIV value for a specific OPB clock frequency
+ */
+static inline u8 iic_clckdiv(unsigned int opb)
+{
+ /* Compatibility kludge, should go away after all cards
+ * are fixed to fill correct value for opbfreq.
+ * Previous driver version used hardcoded divider value 4,
+ * it corresponds to OPB frequency from the range (40, 50] MHz
+ */
+ if (!opb){
+ printk(KERN_WARNING "ibm-iic: using compatibility value for OPB freq,"
+ " fix your board specific setup\n");
+ opb = 50000000;
+ }
+
+ /* Convert to MHz */
+ opb /= 1000000;
+
+ if (opb < 20 || opb > 150){
+ printk(KERN_CRIT "ibm-iic: invalid OPB clock frequency %u MHz\n",
+ opb);
+ opb = opb < 20 ? 20 : 150;
+ }
+ return (u8)((opb + 9) / 10 - 1);
+}
+
+/*
+ * Register single IIC interface
+ */
+static int __devinit iic_probe(struct ocp_device *ocp){
+
+ struct ibm_iic_private* dev;
+ struct i2c_adapter* adap;
+ int ret;
+ bd_t* bd = (bd_t*)&__res;
+
+ if (!(dev = kmalloc(sizeof(*dev), GFP_KERNEL))){
+ printk(KERN_CRIT "ibm-iic: failed to allocate device data\n");
+ return -ENOMEM;
+ }
+
+ memset(dev, 0, sizeof(*dev));
+ dev->idx = ocp->num;
+ ocp_set_drvdata(ocp, dev);
+
+ if (!(dev->vaddr = ioremap(ocp->paddr, sizeof(struct iic_regs)))){
+ printk(KERN_CRIT "ibm-iic%d: failed to ioremap device registers\n",
+ dev->idx);
+ ret = -ENXIO;
+ goto fail2;
+ }
+
+ init_waitqueue_head(&dev->wq);
+
+ dev->irq = iic_force_poll ? -1 : ocp->irq;
+ if (dev->irq >= 0){
+ /* Disable interrupts until we finish intialization,
+ assumes level-sensitive IRQ setup...
+ */
+ 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",
+ dev->idx, dev->irq);
+ /* Fallback to the polling mode */
+ dev->irq = -1;
+ }
+ }
+
+ if (dev->irq < 0)
+ printk(KERN_WARNING "ibm-iic%d: using polling mode\n",
+ dev->idx);
+
+ /* Board specific settings */
+ BUG_ON(dev->idx >= sizeof(bd->bi_iic_fast) / sizeof(bd->bi_iic_fast[0]));
+ dev->fast_mode = iic_force_fast ? 1 : bd->bi_iic_fast[dev->idx];
+
+ /* clckdiv is the same for *all* IIC interfaces,
+ * but I'd rather make a copy than introduce another global. --ebs
+ */
+ dev->clckdiv = iic_clckdiv(bd->bi_opb_busfreq);
+ DBG("%d: clckdiv = %d\n", dev->idx, dev->clckdiv);
+
+ /* Initialize IIC interface */
+ iic_dev_init(dev);
+
+ /* Register it with i2c layer */
+ adap = &dev->adap;
+ strcpy(adap->dev.name, "IBM IIC");
+ i2c_set_adapdata(adap, dev);
+ adap->id = I2C_HW_OCP | iic_algo.id;
+ adap->algo = &iic_algo;
+ adap->client_register = NULL;
+ adap->client_unregister = NULL;
+ adap->timeout = 1;
+ adap->retries = 1;
+
+ if ((ret = i2c_add_adapter(adap)) != 0){
+ printk(KERN_CRIT "ibm-iic%d: failed to register i2c adapter\n",
+ 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)");
+
+ /* Scan bus if requested by user */
+ if (iic_scan)
+ iic_scan_bus(dev);
+
+ return 0;
+
+fail:
+ if (dev->irq >= 0){
+ iic_interrupt_mode(dev, 0);
+ free_irq(dev->irq, dev);
+ }
+
+ iounmap((void*)dev->vaddr);
+fail2:
+ ocp_set_drvdata(ocp, 0);
+ kfree(dev);
+ return ret;
+}
+
+/*
+ * Cleanup initialized IIC interface
+ */
+static void __devexit iic_remove(struct ocp_device *ocp)
+{
+ struct ibm_iic_private* dev = (struct ibm_iic_private*)ocp_get_drvdata(ocp);
+ BUG_ON(dev == NULL);
+ if (i2c_del_adapter(&dev->adap)){
+ printk(KERN_CRIT "ibm-iic%d: failed to delete i2c adapter :(\n",
+ dev->idx);
+ /* That's *very* bad, just shutdown IRQ ... */
+ if (dev->irq >= 0){
+ iic_interrupt_mode(dev, 0);
+ free_irq(dev->irq, dev);
+ dev->irq = -1;
+ }
+ } else {
+ if (dev->irq >= 0){
+ iic_interrupt_mode(dev, 0);
+ free_irq(dev->irq, dev);
+ }
+ iounmap((void*)dev->vaddr);
+ kfree(dev);
+ }
+}
+
+static struct ocp_device_id ibm_iic_ids[] __devinitdata =
+{
+ { .vendor = OCP_VENDOR_IBM, .device = OCP_FUNC_IIC },
+ { .vendor = OCP_VENDOR_INVALID }
+};
+
+MODULE_DEVICE_TABLE(ocp, ibm_iic_ids);
+
+static struct ocp_driver ibm_iic_driver =
+{
+ .name = "ocp_iic",
+ .id_table = ibm_iic_ids,
+ .probe = iic_probe,
+ .remove = __devexit_p(iic_remove),
+#if defined(CONFIG_PM)
+ .suspend = NULL,
+ .resume = NULL,
+#endif
+};
+
+static int __init iic_init(void)
+{
+ printk(KERN_INFO "IBM IIC driver v" DRIVER_VERSION "\n");
+ return ocp_module_init(&ibm_iic_driver);
+}
+
+static void __exit iic_exit(void)
+{
+ ocp_unregister_driver(&ibm_iic_driver);
+}
+
+module_init(iic_init);
+module_exit(iic_exit);
--- /dev/null
+/*
+ * drivers/i2c/i2c-ibm_iic.h
+ *
+ * Support for the IIC peripheral on IBM PPC 4xx
+ *
+ * Copyright (c) 2003 Zultys Technologies.
+ * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
+ *
+ * Based on original work by
+ * Ian DaSilva <idasilva@mvista.com>
+ * Armin Kuster <akuster@mvista.com>
+ * Matt Porter <mporter@mvista.com>
+ *
+ * Copyright 2000-2003 MontaVista Software Inc.
+ *
+ * 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.
+ *
+ */
+#ifndef __I2C_IBM_IIC_H_
+#define __I2C_IBM_IIC_H_
+
+#include <linux/config.h>
+#include <linux/i2c.h>
+
+struct iic_regs {
+ u16 mdbuf;
+ u16 sbbuf;
+ u8 lmadr;
+ u8 hmadr;
+ u8 cntl;
+ u8 mdcntl;
+ u8 sts;
+ u8 extsts;
+ u8 lsadr;
+ u8 hsadr;
+ u8 clkdiv;
+ u8 intmsk;
+ u8 xfrcnt;
+ u8 xtcntlss;
+ u8 directcntl;
+};
+
+struct ibm_iic_private {
+ struct i2c_adapter adap;
+ volatile struct iic_regs *vaddr;
+ wait_queue_head_t wq;
+ int idx;
+ int irq;
+ int fast_mode;
+ u8 clckdiv;
+};
+
+/* IICx_CNTL register */
+#define CNTL_HMT 0x80
+#define CNTL_AMD 0x40
+#define CNTL_TCT_MASK 0x30
+#define CNTL_TCT_SHIFT 4
+#define CNTL_RPST 0x08
+#define CNTL_CHT 0x04
+#define CNTL_RW 0x02
+#define CNTL_PT 0x01
+
+/* IICx_MDCNTL register */
+#define MDCNTL_FSDB 0x80
+#define MDCNTL_FMDB 0x40
+#define MDCNTL_EGC 0x20
+#define MDCNTL_FSM 0x10
+#define MDCNTL_ESM 0x08
+#define MDCNTL_EINT 0x04
+#define MDCNTL_EUBS 0x02
+#define MDCNTL_HSCL 0x01
+
+/* IICx_STS register */
+#define STS_SSS 0x80
+#define STS_SLPR 0x40
+#define STS_MDBS 0x20
+#define STS_MDBF 0x10
+#define STS_SCMP 0x08
+#define STS_ERR 0x04
+#define STS_IRQA 0x02
+#define STS_PT 0x01
+
+/* IICx_EXTSTS register */
+#define EXTSTS_IRQP 0x80
+#define EXTSTS_BCS_MASK 0x70
+#define EXTSTS_BCS_FREE 0x40
+#define EXTSTS_IRQD 0x08
+#define EXTSTS_LA 0x04
+#define EXTSTS_ICT 0x02
+#define EXTSTS_XFRA 0x01
+
+/* IICx_INTRMSK register */
+#define INTRMSK_EIRC 0x80
+#define INTRMSK_EIRS 0x40
+#define INTRMSK_EIWC 0x20
+#define INTRMSK_EIWS 0x10
+#define INTRMSK_EIHE 0x08
+#define INTRMSK_EIIC 0x04
+#define INTRMSK_EITA 0x02
+#define INTRMSK_EIMTC 0x01
+
+/* IICx_XFRCNT register */
+#define XFRCNT_MTC_MASK 0x07
+
+/* IICx_XTCNTLSS register */
+#define XTCNTLSS_SRC 0x80
+#define XTCNTLSS_SRS 0x40
+#define XTCNTLSS_SWC 0x20
+#define XTCNTLSS_SWS 0x10
+#define XTCNTLSS_SRST 0x01
+
+/* IICx_DIRECTCNTL register */
+#define DIRCNTL_SDAC 0x08
+#define DIRCNTL_SCC 0x04
+#define DIRCNTL_MSDA 0x02
+#define DIRCNTL_MSC 0x01
+
+/* Check if we really control the I2C bus and bus is free */
+#define DIRCTNL_FREE(v) (((v) & 0x0f) == 0x0f)
+
+#endif /* __I2C_IBM_IIC_H_ */
--- /dev/null
+/* ------------------------------------------------------------------------- */
+/* i2c-iop3xx.c i2c driver algorithms for Intel XScale IOP3xx */
+/* ------------------------------------------------------------------------- */
+/* Copyright (C) 2003 Peter Milne, D-TACQ Solutions Ltd
+ * <Peter dot Milne at D hyphen TACQ dot com>
+
+ 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, version 2.
+
+
+ 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 acknowledgements to i2c-algo-ibm_ocp.c by
+ Ian DaSilva, MontaVista Software, Inc. idasilva@mvista.com
+
+ And i2c-algo-pcf.c, which was created by Simon G. Vogl and Hans Berglund:
+
+ Copyright (C) 1995-1997 Simon G. Vogl, 1998-2000 Hans Berglund
+
+ And which acknowledged Kyösti Mälkki <kmalkki@cc.hut.fi>,
+ Frodo Looijaard <frodol@dds.nl>, Martin Bailey<mbailey@littlefeet-inc.com>
+
+ ---------------------------------------------------------------------------*/
+
+
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/i2c.h>
+
+
+#include <asm/arch-iop3xx/iop321.h>
+#include <asm/arch-iop3xx/iop321-irqs.h>
+#include "i2c-iop3xx.h"
+
+
+/* ----- global defines ----------------------------------------------- */
+#define PASSERT(x) do { if (!(x) ) \
+ printk(KERN_CRIT "PASSERT %s in %s:%d\n", #x, __FILE__, __LINE__ );\
+ } while (0)
+
+
+/* ----- global variables --------------------------------------------- */
+
+
+static inline unsigned char iic_cook_addr(struct i2c_msg *msg)
+{
+ unsigned char addr;
+
+ addr = (msg->addr << 1);
+
+ if (msg->flags & I2C_M_RD)
+ addr |= 1;
+
+ /* PGM: what is M_REV_DIR_ADDR - do we need it ?? */
+ if (msg->flags & I2C_M_REV_DIR_ADDR)
+ addr ^= 1;
+
+ return addr;
+}
+
+
+static inline void iop3xx_adap_reset(struct i2c_algo_iop3xx_data *iop3xx_adap)
+{
+ /* Follows devman 9.3 */
+ *iop3xx_adap->biu->CR = IOP321_ICR_UNIT_RESET;
+ *iop3xx_adap->biu->SR = IOP321_ISR_CLEARBITS;
+ *iop3xx_adap->biu->CR = 0;
+}
+
+static inline void iop3xx_adap_set_slave_addr(struct i2c_algo_iop3xx_data *iop3xx_adap)
+{
+ *iop3xx_adap->biu->SAR = MYSAR;
+}
+
+static inline void iop3xx_adap_enable(struct i2c_algo_iop3xx_data *iop3xx_adap)
+{
+ u32 cr = IOP321_ICR_GCD|IOP321_ICR_SCLEN|IOP321_ICR_UE;
+
+ /* NB SR bits not same position as CR IE bits :-( */
+ iop3xx_adap->biu->SR_enabled =
+ IOP321_ISR_ALD | IOP321_ISR_BERRD |
+ IOP321_ISR_RXFULL | IOP321_ISR_TXEMPTY;
+
+ cr |= IOP321_ICR_ALDIE | IOP321_ICR_BERRIE |
+ IOP321_ICR_RXFULLIE | IOP321_ICR_TXEMPTYIE;
+
+ *iop3xx_adap->biu->CR = cr;
+}
+
+static void iop3xx_adap_transaction_cleanup(struct i2c_algo_iop3xx_data *iop3xx_adap)
+{
+ unsigned cr = *iop3xx_adap->biu->CR;
+
+ cr &= ~(IOP321_ICR_MSTART | IOP321_ICR_TBYTE |
+ IOP321_ICR_MSTOP | IOP321_ICR_SCLEN);
+ *iop3xx_adap->biu->CR = cr;
+}
+
+static void iop3xx_adap_final_cleanup(struct i2c_algo_iop3xx_data *iop3xx_adap)
+{
+ unsigned cr = *iop3xx_adap->biu->CR;
+
+ cr &= ~(IOP321_ICR_ALDIE | IOP321_ICR_BERRIE |
+ IOP321_ICR_RXFULLIE | IOP321_ICR_TXEMPTYIE);
+ iop3xx_adap->biu->SR_enabled = 0;
+ *iop3xx_adap->biu->CR = cr;
+}
+
+/*
+ * NB: the handler has to clear the source of the interrupt!
+ * Then it passes the SR flags of interest to BH via adap data
+ */
+static void iop3xx_i2c_handler(int this_irq,
+ void *dev_id,
+ struct pt_regs *regs)
+{
+ struct i2c_algo_iop3xx_data *iop3xx_adap = dev_id;
+
+ u32 sr = *iop3xx_adap->biu->SR;
+
+ if ((sr &= iop3xx_adap->biu->SR_enabled)) {
+ *iop3xx_adap->biu->SR = sr;
+ iop3xx_adap->biu->SR_received |= sr;
+ wake_up_interruptible(&iop3xx_adap->waitq);
+ }
+}
+
+/* check all error conditions, clear them , report most important */
+static int iop3xx_adap_error(u32 sr)
+{
+ int rc = 0;
+
+ if ((sr&IOP321_ISR_BERRD)) {
+ if ( !rc ) rc = -I2C_ERR_BERR;
+ }
+ if ((sr&IOP321_ISR_ALD)) {
+ if ( !rc ) rc = -I2C_ERR_ALD;
+ }
+ return rc;
+}
+
+static inline u32 get_srstat(struct i2c_algo_iop3xx_data *iop3xx_adap)
+{
+ unsigned long flags;
+ u32 sr;
+
+ spin_lock_irqsave(&iop3xx_adap->lock, flags);
+ sr = iop3xx_adap->biu->SR_received;
+ iop3xx_adap->biu->SR_received = 0;
+ spin_unlock_irqrestore(&iop3xx_adap->lock, flags);
+
+ return sr;
+}
+
+/*
+ * sleep until interrupted, then recover and analyse the SR
+ * saved by handler
+ */
+typedef int (* compare_func)(unsigned test, unsigned mask);
+/* returns 1 on correct comparison */
+
+static int iop3xx_adap_wait_event(struct i2c_algo_iop3xx_data *iop3xx_adap,
+ unsigned flags, unsigned* status,
+ compare_func compare)
+{
+ unsigned sr = 0;
+ int interrupted;
+ int done;
+ int rc;
+
+ do {
+ interrupted = wait_event_interruptible_timeout (
+ iop3xx_adap->waitq,
+ (done = compare( sr = get_srstat(iop3xx_adap),flags )),
+ iop3xx_adap->timeout
+ );
+ if ((rc = iop3xx_adap_error(sr)) < 0) {
+ *status = sr;
+ return rc;
+ }else if (!interrupted) {
+ *status = sr;
+ return rc = -ETIMEDOUT;
+ }
+ } while(!done);
+
+ *status = sr;
+
+ return rc = 0;
+}
+
+/*
+ * Concrete compare_funcs
+ */
+static int all_bits_clear(unsigned test, unsigned mask)
+{
+ return (test & mask) == 0;
+}
+static int any_bits_set(unsigned test, unsigned mask)
+{
+ return (test & mask) != 0;
+}
+
+static int iop3xx_adap_wait_tx_done(struct i2c_algo_iop3xx_data *iop3xx_adap, int *status)
+{
+ return iop3xx_adap_wait_event(
+ iop3xx_adap,
+ IOP321_ISR_TXEMPTY|IOP321_ISR_ALD|IOP321_ISR_BERRD,
+ status, any_bits_set);
+}
+
+static int iop3xx_adap_wait_rx_done(struct i2c_algo_iop3xx_data *iop3xx_adap, int *status)
+{
+ return iop3xx_adap_wait_event(
+ iop3xx_adap,
+ IOP321_ISR_RXFULL|IOP321_ISR_ALD|IOP321_ISR_BERRD,
+ status, any_bits_set);
+}
+
+static int iop3xx_adap_wait_idle(struct i2c_algo_iop3xx_data *iop3xx_adap, int *status)
+{
+ return iop3xx_adap_wait_event(
+ iop3xx_adap, IOP321_ISR_UNITBUSY, status, all_bits_clear);
+}
+
+/*
+ * Description: This performs the IOP3xx initialization sequence
+ * Valid for IOP321. Maybe valid for IOP310?.
+ */
+static int iop3xx_adap_init (struct i2c_algo_iop3xx_data *iop3xx_adap)
+{
+ *IOP321_GPOD &= ~(iop3xx_adap->channel==0 ?
+ IOP321_GPOD_I2C0:
+ IOP321_GPOD_I2C1);
+
+ iop3xx_adap_reset(iop3xx_adap);
+ iop3xx_adap_set_slave_addr(iop3xx_adap);
+ iop3xx_adap_enable(iop3xx_adap);
+
+ return 0;
+}
+
+static int iop3xx_adap_send_target_slave_addr(struct i2c_algo_iop3xx_data *iop3xx_adap,
+ struct i2c_msg* msg)
+{
+ unsigned cr = *iop3xx_adap->biu->CR;
+ int status;
+ int rc;
+
+ *iop3xx_adap->biu->DBR = iic_cook_addr(msg);
+
+ cr &= ~(IOP321_ICR_MSTOP | IOP321_ICR_NACK);
+ cr |= IOP321_ICR_MSTART | IOP321_ICR_TBYTE;
+
+ *iop3xx_adap->biu->CR = cr;
+ rc = iop3xx_adap_wait_tx_done(iop3xx_adap, &status);
+ /* this assert fires every time, contrary to IOP manual
+ PASSERT((status&IOP321_ISR_UNITBUSY)!=0);
+ */
+ PASSERT((status&IOP321_ISR_RXREAD)==0);
+
+ return rc;
+}
+
+static int iop3xx_adap_write_byte(struct i2c_algo_iop3xx_data *iop3xx_adap, char byte, int stop)
+{
+ unsigned cr = *iop3xx_adap->biu->CR;
+ int status;
+ int rc;
+
+ *iop3xx_adap->biu->DBR = byte;
+ cr &= ~IOP321_ICR_MSTART;
+ if (stop) {
+ cr |= IOP321_ICR_MSTOP;
+ } else {
+ cr &= ~IOP321_ICR_MSTOP;
+ }
+ *iop3xx_adap->biu->CR = cr |= IOP321_ICR_TBYTE;
+ rc = iop3xx_adap_wait_tx_done(iop3xx_adap, &status);
+
+ return rc;
+}
+
+static int iop3xx_adap_read_byte(struct i2c_algo_iop3xx_data *iop3xx_adap,
+ char* byte, int stop)
+{
+ unsigned cr = *iop3xx_adap->biu->CR;
+ int status;
+ int rc;
+
+ cr &= ~IOP321_ICR_MSTART;
+
+ if (stop) {
+ cr |= IOP321_ICR_MSTOP|IOP321_ICR_NACK;
+ } else {
+ cr &= ~(IOP321_ICR_MSTOP|IOP321_ICR_NACK);
+ }
+ *iop3xx_adap->biu->CR = cr |= IOP321_ICR_TBYTE;
+
+ rc = iop3xx_adap_wait_rx_done(iop3xx_adap, &status);
+
+ *byte = *iop3xx_adap->biu->DBR;
+
+ return rc;
+}
+
+static int iop3xx_i2c_writebytes(struct i2c_adapter *i2c_adap,
+ const char *buf, int count)
+{
+ struct i2c_algo_iop3xx_data *iop3xx_adap = i2c_adap->algo_data;
+ int ii;
+ int rc = 0;
+
+ for (ii = 0; rc == 0 && ii != count; ++ii) {
+ rc = iop3xx_adap_write_byte(iop3xx_adap, buf[ii], ii==count-1);
+ }
+ return rc;
+}
+
+static int iop3xx_i2c_readbytes(struct i2c_adapter *i2c_adap,
+ char *buf, int count)
+{
+ struct i2c_algo_iop3xx_data *iop3xx_adap = i2c_adap->algo_data;
+ int ii;
+ int rc = 0;
+
+ for (ii = 0; rc == 0 && ii != count; ++ii) {
+ rc = iop3xx_adap_read_byte(iop3xx_adap, &buf[ii], ii==count-1);
+ }
+ return rc;
+}
+
+/*
+ * Description: This function implements combined transactions. Combined
+ * transactions consist of combinations of reading and writing blocks of data.
+ * FROM THE SAME ADDRESS
+ * Each transfer (i.e. a read or a write) is separated by a repeated start
+ * condition.
+ */
+static int iop3xx_handle_msg(struct i2c_adapter *i2c_adap, struct i2c_msg* pmsg)
+{
+ struct i2c_algo_iop3xx_data *iop3xx_adap = i2c_adap->algo_data;
+ int rc;
+
+ rc = iop3xx_adap_send_target_slave_addr(iop3xx_adap, pmsg);
+ if (rc < 0) {
+ return rc;
+ }
+
+ if ((pmsg->flags&I2C_M_RD)) {
+ return iop3xx_i2c_readbytes(i2c_adap, pmsg->buf, pmsg->len);
+ } else {
+ return iop3xx_i2c_writebytes(i2c_adap, pmsg->buf, pmsg->len);
+ }
+}
+
+/*
+ * master_xfer() - main read/write entry
+ */
+static int iop3xx_master_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num)
+{
+ struct i2c_algo_iop3xx_data *iop3xx_adap = i2c_adap->algo_data;
+ int im = 0;
+ int ret = 0;
+ int status;
+
+ iop3xx_adap_wait_idle(iop3xx_adap, &status);
+ iop3xx_adap_reset(iop3xx_adap);
+ iop3xx_adap_enable(iop3xx_adap);
+
+ for (im = 0; ret == 0 && im != num; ++im) {
+ ret = iop3xx_handle_msg(i2c_adap, &msgs[im]);
+ }
+
+ iop3xx_adap_transaction_cleanup(iop3xx_adap);
+
+ return ret;
+}
+
+static int algo_control(struct i2c_adapter *adapter, unsigned int cmd,
+ unsigned long arg)
+{
+ return 0;
+}
+
+static u32 iic_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+
+/* -----exported algorithm data: ------------------------------------- */
+
+static struct i2c_algorithm iic_algo = {
+ .name = "IOP3xx I2C algorithm",
+ .id = I2C_ALGO_OCP_IOP3XX,
+ .master_xfer = iop3xx_master_xfer,
+ .algo_control = algo_control,
+ .functionality = iic_func,
+};
+
+/*
+ * registering functions to load algorithms at runtime
+ */
+static int i2c_iop3xx_add_bus(struct i2c_adapter *iic_adap)
+{
+ struct i2c_algo_iop3xx_data *iop3xx_adap = iic_adap->algo_data;
+
+ if (!request_region( REGION_START(iop3xx_adap),
+ REGION_LENGTH(iop3xx_adap),
+ iic_adap->name)) {
+ return -ENODEV;
+ }
+
+ init_waitqueue_head(&iop3xx_adap->waitq);
+ spin_lock_init(&iop3xx_adap->lock);
+
+ if (request_irq(
+ iop3xx_adap->biu->irq,
+ iop3xx_i2c_handler,
+ /* SA_SAMPLE_RANDOM */ 0,
+ iic_adap->name,
+ iop3xx_adap)) {
+ return -ENODEV;
+ }
+
+ /* register new iic_adapter to i2c module... */
+ iic_adap->id |= iic_algo.id;
+ iic_adap->algo = &iic_algo;
+
+ iic_adap->timeout = 100; /* default values, should */
+ iic_adap->retries = 3; /* be replaced by defines */
+
+ iop3xx_adap_init(iic_adap->algo_data);
+ i2c_add_adapter(iic_adap);
+ return 0;
+}
+
+static int i2c_iop3xx_del_bus(struct i2c_adapter *iic_adap)
+{
+ struct i2c_algo_iop3xx_data *iop3xx_adap = iic_adap->algo_data;
+
+ iop3xx_adap_final_cleanup(iop3xx_adap);
+ free_irq(iop3xx_adap->biu->irq, iop3xx_adap);
+
+ release_region(REGION_START(iop3xx_adap), REGION_LENGTH(iop3xx_adap));
+
+ return i2c_del_adapter(iic_adap);
+}
+
+#ifdef CONFIG_ARCH_IOP321
+
+static struct iop3xx_biu biu0 = {
+ .CR = IOP321_ICR0,
+ .SR = IOP321_ISR0,
+ .SAR = IOP321_ISAR0,
+ .DBR = IOP321_IDBR0,
+ .BMR = IOP321_IBMR0,
+ .irq = IRQ_IOP321_I2C_0,
+};
+
+static struct iop3xx_biu biu1 = {
+ .CR = IOP321_ICR1,
+ .SR = IOP321_ISR1,
+ .SAR = IOP321_ISAR1,
+ .DBR = IOP321_IDBR1,
+ .BMR = IOP321_IBMR1,
+ .irq = IRQ_IOP321_I2C_1,
+};
+
+#define ADAPTER_NAME_ROOT "IOP321 i2c biu adapter "
+#else
+#error Please define the BIU struct iop3xx_biu for your processor arch
+#endif
+
+static struct i2c_algo_iop3xx_data algo_iop3xx_data0 = {
+ .channel = 0,
+ .biu = &biu0,
+ .timeout = 1*HZ,
+};
+static struct i2c_algo_iop3xx_data algo_iop3xx_data1 = {
+ .channel = 1,
+ .biu = &biu1,
+ .timeout = 1*HZ,
+};
+
+static struct i2c_adapter iop3xx_ops0 = {
+ .owner = THIS_MODULE,
+ .name = ADAPTER_NAME_ROOT "0",
+ .id = I2C_HW_IOP321,
+ .algo_data = &algo_iop3xx_data0,
+};
+static struct i2c_adapter iop3xx_ops1 = {
+ .owner = THIS_MODULE,
+ .name = ADAPTER_NAME_ROOT "1",
+ .id = I2C_HW_IOP321,
+ .algo_data = &algo_iop3xx_data1,
+};
+
+static int __init i2c_iop3xx_init (void)
+{
+ return i2c_iop3xx_add_bus(&iop3xx_ops0) ||
+ i2c_iop3xx_add_bus(&iop3xx_ops1);
+}
+
+static void __exit i2c_iop3xx_exit (void)
+{
+ i2c_iop3xx_del_bus(&iop3xx_ops0);
+ i2c_iop3xx_del_bus(&iop3xx_ops1);
+}
+
+module_init (i2c_iop3xx_init);
+module_exit (i2c_iop3xx_exit);
+
+MODULE_AUTHOR("D-TACQ Solutions Ltd <www.d-tacq.com>");
+MODULE_DESCRIPTION("IOP3xx iic algorithm and driver");
+MODULE_LICENSE("GPL");
+
+MODULE_PARM(i2c_debug,"i");
+
+MODULE_PARM_DESC(i2c_debug, "debug level - 0 off; 1 normal; 2,3 more verbose; 9 iic-protocol");
+
--- /dev/null
+/* ------------------------------------------------------------------------- */
+/* i2c-iop3xx.h algorithm driver definitions private to i2c-iop3xx.c */
+/* ------------------------------------------------------------------------- */
+/* Copyright (C) 2003 Peter Milne, D-TACQ Solutions Ltd
+ * <Peter dot Milne at D hyphen TACQ dot com>
+
+ 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, version 2.
+
+ 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_IOP3XX_H
+#define I2C_IOP3XX_H 1
+
+/*
+ * iop321 hardware bit definitions
+ */
+#define IOP321_ICR_FAST_MODE 0x8000 /* 1=400kBps, 0=100kBps */
+#define IOP321_ICR_UNIT_RESET 0x4000 /* 1=RESET */
+#define IOP321_ICR_SADIE 0x2000 /* 1=Slave Detect Interrupt Enable */
+#define IOP321_ICR_ALDIE 0x1000 /* 1=Arb Loss Detect Interrupt Enable */
+#define IOP321_ICR_SSDIE 0x0800 /* 1=Slave STOP Detect Interrupt Enable */
+#define IOP321_ICR_BERRIE 0x0400 /* 1=Bus Error Interrupt Enable */
+#define IOP321_ICR_RXFULLIE 0x0200 /* 1=Receive Full Interrupt Enable */
+#define IOP321_ICR_TXEMPTYIE 0x0100 /* 1=Transmit Empty Interrupt Enable */
+#define IOP321_ICR_GCD 0x0080 /* 1=General Call Disable */
+/*
+ * IOP321_ICR_GCD: 1 disables response as slave. "This bit must be set
+ * when sending a master mode general call message from the I2C unit"
+ */
+#define IOP321_ICR_UE 0x0040 /* 1=Unit Enable */
+/*
+ * "NOTE: To avoid I2C bus integrity problems,
+ * the user needs to ensure that the GPIO Output Data Register -
+ * GPOD bits associated with an I2C port are cleared prior to setting
+ * the enable bit for that I2C serial port.
+ * The user prepares to enable I2C port 0 and
+ * I2C port 1 by clearing GPOD bits 7:6 and GPOD bits 5:4, respectively.
+ */
+#define IOP321_ICR_SCLEN 0x0020 /* 1=SCL enable for master mode */
+#define IOP321_ICR_MABORT 0x0010 /* 1=Send a STOP with no data
+ * NB TBYTE must be clear */
+#define IOP321_ICR_TBYTE 0x0008 /* 1=Send/Receive a byte. i2c clears */
+#define IOP321_ICR_NACK 0x0004 /* 1=reply with NACK */
+#define IOP321_ICR_MSTOP 0x0002 /* 1=send a STOP after next data byte */
+#define IOP321_ICR_MSTART 0x0001 /* 1=initiate a START */
+
+
+#define IOP321_ISR_BERRD 0x0400 /* 1=BUS ERROR Detected */
+#define IOP321_ISR_SAD 0x0200 /* 1=Slave ADdress Detected */
+#define IOP321_ISR_GCAD 0x0100 /* 1=General Call Address Detected */
+#define IOP321_ISR_RXFULL 0x0080 /* 1=Receive Full */
+#define IOP321_ISR_TXEMPTY 0x0040 /* 1=Transmit Empty */
+#define IOP321_ISR_ALD 0x0020 /* 1=Arbitration Loss Detected */
+#define IOP321_ISR_SSD 0x0010 /* 1=Slave STOP Detected */
+#define IOP321_ISR_BBUSY 0x0008 /* 1=Bus BUSY */
+#define IOP321_ISR_UNITBUSY 0x0004 /* 1=Unit Busy */
+#define IOP321_ISR_NACK 0x0002 /* 1=Unit Rx or Tx a NACK */
+#define IOP321_ISR_RXREAD 0x0001 /* 1=READ 0=WRITE (R/W bit of slave addr */
+
+#define IOP321_ISR_CLEARBITS 0x07f0
+
+#define IOP321_ISAR_SAMASK 0x007f
+
+#define IOP321_IDBR_MASK 0x00ff
+
+#define IOP321_IBMR_SCL 0x0002
+#define IOP321_IBMR_SDA 0x0001
+
+#define IOP321_GPOD_I2C0 0x00c0 /* clear these bits to enable ch0 */
+#define IOP321_GPOD_I2C1 0x0030 /* clear these bits to enable ch1 */
+
+#define MYSAR 0x02 /* SWAG a suitable slave address */
+
+#define I2C_ERR 321
+#define I2C_ERR_BERR (I2C_ERR+0)
+#define I2C_ERR_ALD (I2C_ERR+1)
+
+
+struct iop3xx_biu { /* Bus Interface Unit - the hardware */
+/* physical hardware defs - regs*/
+ u32 *CR;
+ u32 *SR;
+ u32 *SAR;
+ u32 *DBR;
+ u32 *BMR;
+/* irq bit vector */
+ u32 irq;
+/* stored flags */
+ u32 SR_enabled, SR_received;
+};
+
+struct i2c_algo_iop3xx_data {
+ int channel;
+
+ wait_queue_head_t waitq;
+ spinlock_t lock;
+ int timeout;
+ struct iop3xx_biu* biu;
+};
+
+#define REGION_START(adap) ((u32)((adap)->biu->CR))
+#define REGION_END(adap) ((u32)((adap)->biu->BMR+1))
+#define REGION_LENGTH(adap) (REGION_END(adap)-REGION_START(adap))
+
+#define IRQ_STATUS_MASK(adap) (1<<adap->biu->irq)
+
+#endif /* I2C_IOP3XX_H */
--- /dev/null
+/*
+ -------------------------------------------------------------------------
+ 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 <kmalkki@cc.hut.fi> and even
+ Frodo Looijaard <frodol@dds.nl> */
+
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+
+#include <linux/i2c.h>
+#include <linux/i2c-algo-ite.h>
+#include <linux/i2c-adap-ite.h>
+#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 = 0;
+static int irq = 0;
+static int clock = 0;
+static int own = 0;
+
+static int i2c_debug=0;
+static struct iic_ite gpi;
+static wait_queue_head_t iic_wait;
+static int iic_pending;
+
+/* ----- global defines ----------------------------------------------- */
+#define DEB(x) if (i2c_debug>=1) x
+#define DEB2(x) if (i2c_debug>=2) x
+#define DEB3(x) if (i2c_debug>=3) x
+#define DEBE(x) x /* error messages */
+
+
+/* ----- local functions ---------------------------------------------- */
+
+static void iic_ite_setiic(void *data, int ctl, short val)
+{
+ unsigned long j = jiffies + 10;
+
+ DEB3(printk(" Write 0x%02x to 0x%x\n",(unsigned short)val, ctl&0xff));
+ DEB3({while (time_before(jiffies, j)) schedule();})
+ outw(val,ctl);
+}
+
+static short iic_ite_getiic(void *data, int ctl)
+{
+ short val;
+
+ val = inw(ctl);
+ DEB3(printk("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);
+}
+
+
+#if 0
+static void iic_ite_sleep(unsigned long timeout)
+{
+ schedule_timeout( timeout * HZ);
+}
+#endif
+
+
+/* Put this process to sleep. We will wake up when the
+ * IIC controller interrupts.
+ */
+static void iic_ite_waitforpin(void) {
+
+ int timeout = 2;
+
+ /* 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) {
+ cli();
+ if (iic_pending == 0) {
+ interruptible_sleep_on_timeout(&iic_wait, timeout*HZ );
+ } else
+ iic_pending = 0;
+ sti();
+ } else {
+ udelay(100);
+ }
+}
+
+
+static void iic_ite_handler(int this_irq, void *dev_id, struct pt_regs *regs)
+{
+
+ iic_pending = 1;
+
+ DEB2(printk("iic_ite_handler: in interrupt handler\n"));
+ wake_up_interruptible(&iic_wait);
+}
+
+
+/* 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,
+ .dev = {
+ .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);
+ 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 <www.mvista.com>");
+MODULE_DESCRIPTION("I2C-Bus adapter routines for ITE IIC bus adapter");
+MODULE_LICENSE("GPL");
+
+MODULE_PARM(base, "i");
+MODULE_PARM(irq, "i");
+MODULE_PARM(clock, "i");
+MODULE_PARM(own, "i");
+MODULE_PARM(i2c_debug,"i");
+
+
+/* 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);
--- /dev/null
+/*
+ i2c Support for Apple Keywest I2C Bus Controller
+
+ Copyright (c) 2001 Benjamin Herrenschmidt <benh@kernel.crashing.org>
+
+ Original work by
+
+ Copyright (c) 2000 Philip Edelbrock <phil@stimpy.netroedge.com>
+
+ 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.
+
+ Changes:
+
+ 2001/12/13 BenH New implementation
+ 2001/12/15 BenH Add support for "byte" and "quick"
+ transfers. Add i2c_xfer routine.
+
+ My understanding of the various modes supported by keywest are:
+
+ - Dumb mode : not implemented, probably direct tweaking of lines
+ - Standard mode : simple i2c transaction of type
+ S Addr R/W A Data A Data ... T
+ - Standard sub mode : combined 8 bit subaddr write with data read
+ S Addr R/W A SubAddr A Data A Data ... T
+ - Combined mode : Subaddress and Data sequences appended with no stop
+ S Addr R/W A SubAddr S Addr R/W A Data A Data ... T
+
+ Currently, this driver uses only Standard mode for i2c xfer, and
+ smbus byte & quick transfers ; and uses StandardSub mode for
+ other smbus transfers instead of combined as we need that for the
+ sound driver to be happy
+*/
+
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/timer.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/interrupt.h>
+
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/machdep.h>
+#include <asm/pmac_feature.h>
+
+#include "i2c-keywest.h"
+
+#define DBG(x...) do {\
+ if (debug > 0) \
+ printk(KERN_DEBUG "KW:" x); \
+ } while(0)
+
+
+MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
+MODULE_DESCRIPTION("I2C driver for Apple's Keywest");
+MODULE_LICENSE("GPL");
+MODULE_PARM(probe, "i");
+MODULE_PARM(debug, "i");
+
+int probe = 0;
+int debug = 0;
+
+static void
+do_stop(struct keywest_iface* iface, int result)
+{
+ write_reg(reg_control, read_reg(reg_control) | KW_I2C_CTL_STOP);
+ iface->state = state_stop;
+ iface->result = result;
+}
+
+/* Main state machine for standard & standard sub mode */
+static int
+handle_interrupt(struct keywest_iface *iface, u8 isr)
+{
+ int ack;
+ int rearm_timer = 1;
+
+ DBG("handle_interrupt(), got: %x, status: %x, state: %d\n",
+ isr, read_reg(reg_status), iface->state);
+ if (isr == 0 && iface->state != state_stop) {
+ do_stop(iface, -1);
+ return rearm_timer;
+ }
+ if (isr & KW_I2C_IRQ_STOP && iface->state != state_stop) {
+ iface->result = -1;
+ iface->state = state_stop;
+ }
+ switch(iface->state) {
+ case state_addr:
+ if (!(isr & KW_I2C_IRQ_ADDR)) {
+ do_stop(iface, -1);
+ break;
+ }
+ ack = read_reg(reg_status);
+ DBG("ack on set address: %x\n", ack);
+ if ((ack & KW_I2C_STAT_LAST_AAK) == 0) {
+ do_stop(iface, -1);
+ break;
+ }
+ /* Handle rw "quick" mode */
+ if (iface->datalen == 0)
+ do_stop(iface, 0);
+ else if (iface->read_write == I2C_SMBUS_READ) {
+ iface->state = state_read;
+ if (iface->datalen > 1)
+ write_reg(reg_control, read_reg(reg_control)
+ | KW_I2C_CTL_AAK);
+ } else {
+ iface->state = state_write;
+ DBG("write byte: %x\n", *(iface->data));
+ write_reg(reg_data, *(iface->data++));
+ iface->datalen--;
+ }
+
+ break;
+ case state_read:
+ if (!(isr & KW_I2C_IRQ_DATA)) {
+ do_stop(iface, -1);
+ break;
+ }
+ *(iface->data++) = read_reg(reg_data);
+ DBG("read byte: %x\n", *(iface->data-1));
+ iface->datalen--;
+ if (iface->datalen == 0)
+ iface->state = state_stop;
+ else
+ write_reg(reg_control, 0);
+ break;
+ case state_write:
+ if (!(isr & KW_I2C_IRQ_DATA)) {
+ do_stop(iface, -1);
+ break;
+ }
+ /* Check ack status */
+ ack = read_reg(reg_status);
+ DBG("ack on data write: %x\n", ack);
+ if ((ack & KW_I2C_STAT_LAST_AAK) == 0) {
+ do_stop(iface, -1);
+ break;
+ }
+ if (iface->datalen) {
+ DBG("write byte: %x\n", *(iface->data));
+ write_reg(reg_data, *(iface->data++));
+ iface->datalen--;
+ } else
+ do_stop(iface, 0);
+ break;
+
+ case state_stop:
+ if (!(isr & KW_I2C_IRQ_STOP) && (++iface->stopretry) < 10)
+ do_stop(iface, -1);
+ else {
+ rearm_timer = 0;
+ iface->state = state_idle;
+ write_reg(reg_control, 0x00);
+ write_reg(reg_ier, 0x00);
+ complete(&iface->complete);
+ }
+ break;
+ }
+
+ write_reg(reg_isr, isr);
+
+ return rearm_timer;
+}
+
+/* Interrupt handler */
+static irqreturn_t
+keywest_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct keywest_iface *iface = (struct keywest_iface *)dev_id;
+
+ spin_lock(&iface->lock);
+ del_timer(&iface->timeout_timer);
+ if (handle_interrupt(iface, read_reg(reg_isr)))
+ mod_timer(&iface->timeout_timer, jiffies + POLL_TIMEOUT);
+ spin_unlock(&iface->lock);
+ return IRQ_HANDLED;
+}
+
+static void
+keywest_timeout(unsigned long data)
+{
+ struct keywest_iface *iface = (struct keywest_iface *)data;
+
+ DBG("timeout !\n");
+ spin_lock_irq(&iface->lock);
+ if (handle_interrupt(iface, read_reg(reg_isr)))
+ mod_timer(&iface->timeout_timer, jiffies + POLL_TIMEOUT);
+ spin_unlock(&iface->lock);
+}
+
+/*
+ * SMBUS-type transfer entrypoint
+ */
+static s32
+keywest_smbus_xfer( struct i2c_adapter* adap,
+ u16 addr,
+ unsigned short flags,
+ char read_write,
+ u8 command,
+ int size,
+ union i2c_smbus_data* data)
+{
+ struct keywest_chan* chan = i2c_get_adapdata(adap);
+ struct keywest_iface* iface = chan->iface;
+ int len;
+ u8* buffer;
+ u16 cur_word;
+ int rc = 0;
+
+ if (iface->state == state_dead)
+ return -1;
+
+ /* Prepare datas & select mode */
+ iface->cur_mode &= ~KW_I2C_MODE_MODE_MASK;
+ switch (size) {
+ case I2C_SMBUS_QUICK:
+ len = 0;
+ buffer = NULL;
+ iface->cur_mode |= KW_I2C_MODE_STANDARD;
+ break;
+ case I2C_SMBUS_BYTE:
+ len = 1;
+ buffer = &data->byte;
+ iface->cur_mode |= KW_I2C_MODE_STANDARD;
+ break;
+ case I2C_SMBUS_BYTE_DATA:
+ len = 1;
+ buffer = &data->byte;
+ iface->cur_mode |= KW_I2C_MODE_STANDARDSUB;
+ break;
+ case I2C_SMBUS_WORD_DATA:
+ len = 2;
+ cur_word = cpu_to_le16(data->word);
+ buffer = (u8 *)&cur_word;
+ iface->cur_mode |= KW_I2C_MODE_STANDARDSUB;
+ break;
+ case I2C_SMBUS_BLOCK_DATA:
+ len = data->block[0];
+ buffer = &data->block[1];
+ iface->cur_mode |= KW_I2C_MODE_STANDARDSUB;
+ break;
+ default:
+ return -1;
+ }
+
+ /* Original driver had this limitation */
+ if (len > 32)
+ len = 32;
+
+ down(&iface->sem);
+
+ DBG("chan: %d, addr: 0x%x, transfer len: %d, read: %d\n",
+ chan->chan_no, addr, len, read_write == I2C_SMBUS_READ);
+
+ iface->data = buffer;
+ iface->datalen = len;
+ iface->state = state_addr;
+ iface->result = 0;
+ iface->stopretry = 0;
+ iface->read_write = read_write;
+
+ /* Setup channel & clear pending irqs */
+ write_reg(reg_mode, iface->cur_mode | (chan->chan_no << 4));
+ write_reg(reg_isr, read_reg(reg_isr));
+ write_reg(reg_status, 0);
+
+ /* Set up address and r/w bit */
+ write_reg(reg_addr,
+ (addr << 1) | ((read_write == I2C_SMBUS_READ) ? 0x01 : 0x00));
+
+ /* Set up the sub address */
+ if ((iface->cur_mode & KW_I2C_MODE_MODE_MASK) == KW_I2C_MODE_STANDARDSUB
+ || (iface->cur_mode & KW_I2C_MODE_MODE_MASK) == KW_I2C_MODE_COMBINED)
+ write_reg(reg_subaddr, command);
+
+ /* Arm timeout */
+ mod_timer(&iface->timeout_timer, jiffies + POLL_TIMEOUT);
+
+ /* Start sending address & enable interrupt*/
+ write_reg(reg_control, read_reg(reg_control) | KW_I2C_CTL_XADDR);
+ write_reg(reg_ier, KW_I2C_IRQ_MASK);
+
+ /* Wait interrupt operations completion */
+ wait_for_completion(&iface->complete);
+
+ rc = iface->result;
+ DBG("transfer done, result: %d\n", rc);
+
+ if (rc == 0 && size == I2C_SMBUS_WORD_DATA && read_write == I2C_SMBUS_READ)
+ data->word = le16_to_cpu(cur_word);
+
+ /* Release sem */
+ up(&iface->sem);
+
+ return rc;
+}
+
+/*
+ * Generic i2c master transfer entrypoint
+ */
+static int
+keywest_xfer( struct i2c_adapter *adap,
+ struct i2c_msg msgs[],
+ int num)
+{
+ struct keywest_chan* chan = i2c_get_adapdata(adap);
+ struct keywest_iface* iface = chan->iface;
+ struct i2c_msg *pmsg;
+ int i, completed;
+ int rc = 0;
+
+ down(&iface->sem);
+
+ /* Set adapter to standard mode */
+ iface->cur_mode &= ~KW_I2C_MODE_MODE_MASK;
+ iface->cur_mode |= KW_I2C_MODE_STANDARD;
+
+ completed = 0;
+ for (i = 0; rc >= 0 && i < num;) {
+ u8 addr;
+
+ pmsg = &msgs[i++];
+ addr = pmsg->addr;
+ if (pmsg->flags & I2C_M_TEN) {
+ printk(KERN_ERR "i2c-keywest: 10 bits addr not supported !\n");
+ rc = -EINVAL;
+ break;
+ }
+ DBG("xfer: chan: %d, doing %s %d bytes to 0x%02x - %d of %d messages\n",
+ chan->chan_no,
+ pmsg->flags & I2C_M_RD ? "read" : "write",
+ pmsg->len, addr, i, num);
+
+ /* Setup channel & clear pending irqs */
+ write_reg(reg_mode, iface->cur_mode | (chan->chan_no << 4));
+ write_reg(reg_isr, read_reg(reg_isr));
+ write_reg(reg_status, 0);
+
+ iface->data = pmsg->buf;
+ iface->datalen = pmsg->len;
+ iface->state = state_addr;
+ iface->result = 0;
+ iface->stopretry = 0;
+ if (pmsg->flags & I2C_M_RD)
+ iface->read_write = I2C_SMBUS_READ;
+ else
+ iface->read_write = I2C_SMBUS_WRITE;
+
+ /* Set up address and r/w bit */
+ if (pmsg->flags & I2C_M_REV_DIR_ADDR)
+ addr ^= 1;
+ write_reg(reg_addr,
+ (addr << 1) |
+ ((iface->read_write == I2C_SMBUS_READ) ? 0x01 : 0x00));
+
+ /* Arm timeout */
+ mod_timer(&iface->timeout_timer, jiffies + POLL_TIMEOUT);
+
+ /* Start sending address & enable interrupt*/
+ write_reg(reg_control, read_reg(reg_control) | KW_I2C_CTL_XADDR);
+ write_reg(reg_ier, KW_I2C_IRQ_MASK);
+
+ /* Wait interrupt operations completion */
+ wait_for_completion(&iface->complete);
+
+ rc = iface->result;
+ if (rc == 0)
+ completed++;
+ DBG("transfer done, result: %d\n", rc);
+ }
+
+ /* Release sem */
+ up(&iface->sem);
+
+ return completed;
+}
+
+static u32
+keywest_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;
+}
+
+/* For now, we only handle combined mode (smbus) */
+static struct i2c_algorithm keywest_algorithm = {
+ .name = "Keywest i2c",
+ .id = I2C_ALGO_SMBUS,
+ .smbus_xfer = keywest_smbus_xfer,
+ .master_xfer = keywest_xfer,
+ .functionality = keywest_func,
+};
+
+
+static int
+create_iface(struct device_node *np, struct device *dev)
+{
+ unsigned long steps, *psteps, *prate;
+ unsigned bsteps, tsize, i, nchan, addroffset;
+ struct keywest_iface* iface;
+ int rc;
+
+ psteps = (unsigned long *)get_property(np, "AAPL,address-step", NULL);
+ steps = psteps ? (*psteps) : 0x10;
+
+ /* Hrm... maybe we can be smarter here */
+ for (bsteps = 0; (steps & 0x01) == 0; bsteps++)
+ steps >>= 1;
+
+ if (!strcmp(np->parent->name, "uni-n")) {
+ nchan = 2;
+ addroffset = 3;
+ } else {
+ addroffset = 0;
+ nchan = 1;
+ }
+
+ tsize = sizeof(struct keywest_iface) +
+ (sizeof(struct keywest_chan) + 4) * nchan;
+ iface = (struct keywest_iface *) kmalloc(tsize, GFP_KERNEL);
+ if (iface == NULL) {
+ printk(KERN_ERR "i2c-keywest: can't allocate inteface !\n");
+ return -ENOMEM;
+ }
+ memset(iface, 0, tsize);
+ init_MUTEX(&iface->sem);
+ spin_lock_init(&iface->lock);
+ init_completion(&iface->complete);
+ iface->bsteps = bsteps;
+ iface->chan_count = nchan;
+ iface->state = state_idle;
+ iface->irq = np->intrs[0].line;
+ iface->channels = (struct keywest_chan *)
+ (((unsigned long)(iface + 1) + 3UL) & ~3UL);
+ iface->base = (unsigned long)ioremap(np->addrs[0].address + addroffset,
+ np->addrs[0].size);
+ if (iface->base == 0) {
+ printk(KERN_ERR "i2c-keywest: can't map inteface !\n");
+ kfree(iface);
+ return -ENOMEM;
+ }
+
+ init_timer(&iface->timeout_timer);
+ iface->timeout_timer.function = keywest_timeout;
+ iface->timeout_timer.data = (unsigned long)iface;
+
+ /* Select interface rate */
+ iface->cur_mode = KW_I2C_MODE_100KHZ;
+ prate = (unsigned long *)get_property(np, "AAPL,i2c-rate", NULL);
+ if (prate) switch(*prate) {
+ case 100:
+ iface->cur_mode = KW_I2C_MODE_100KHZ;
+ break;
+ case 50:
+ iface->cur_mode = KW_I2C_MODE_50KHZ;
+ break;
+ case 25:
+ iface->cur_mode = KW_I2C_MODE_25KHZ;
+ break;
+ default:
+ printk(KERN_WARNING "i2c-keywest: unknown rate %ldKhz, using 100KHz\n",
+ *prate);
+ }
+
+ /* Select standard sub mode */
+ iface->cur_mode |= KW_I2C_MODE_STANDARDSUB;
+
+ /* Write mode */
+ write_reg(reg_mode, iface->cur_mode);
+
+ /* Switch interrupts off & clear them*/
+ write_reg(reg_ier, 0x00);
+ write_reg(reg_isr, KW_I2C_IRQ_MASK);
+
+ /* Request chip interrupt */
+ rc = request_irq(iface->irq, keywest_irq, 0, "keywest i2c", iface);
+ if (rc) {
+ printk(KERN_ERR "i2c-keywest: can't get IRQ %d !\n", iface->irq);
+ iounmap((void *)iface->base);
+ kfree(iface);
+ return -ENODEV;
+ }
+
+ dev_set_drvdata(dev, iface);
+
+ for (i=0; i<nchan; i++) {
+ struct keywest_chan* chan = &iface->channels[i];
+ u8 addr;
+
+ sprintf(chan->adapter.name, "%s %d", np->parent->name, i);
+ chan->iface = iface;
+ chan->chan_no = i;
+ chan->adapter.id = I2C_ALGO_SMBUS;
+ chan->adapter.algo = &keywest_algorithm;
+ chan->adapter.algo_data = NULL;
+ chan->adapter.client_register = NULL;
+ chan->adapter.client_unregister = NULL;
+ i2c_set_adapdata(&chan->adapter, chan);
+ chan->adapter.dev.parent = dev;
+
+ rc = i2c_add_adapter(&chan->adapter);
+ if (rc) {
+ printk("i2c-keywest.c: Adapter %s registration failed\n",
+ chan->adapter.name);
+ i2c_set_adapdata(&chan->adapter, NULL);
+ }
+ if (probe) {
+ printk("Probe: ");
+ for (addr = 0x00; addr <= 0x7f; addr++) {
+ if (i2c_smbus_xfer(&chan->adapter,addr,
+ 0,0,0,I2C_SMBUS_QUICK,NULL) >= 0)
+ printk("%02x ", addr);
+ }
+ printk("\n");
+ }
+ }
+
+ printk(KERN_INFO "Found KeyWest i2c on \"%s\", %d channel%s, stepping: %d bits\n",
+ np->parent->name, nchan, nchan > 1 ? "s" : "", bsteps);
+
+ return 0;
+}
+
+static int
+dispose_iface(struct device *dev)
+{
+ struct keywest_iface *iface = dev_get_drvdata(dev);
+ int i, rc;
+
+ /* Make sure we stop all activity */
+ down(&iface->sem);
+
+ spin_lock_irq(&iface->lock);
+ while (iface->state != state_idle) {
+ spin_unlock_irq(&iface->lock);
+ set_task_state(current,TASK_UNINTERRUPTIBLE);
+ schedule_timeout(HZ/10);
+ spin_lock_irq(&iface->lock);
+ }
+ iface->state = state_dead;
+ spin_unlock_irq(&iface->lock);
+ free_irq(iface->irq, iface);
+ up(&iface->sem);
+
+ /* Release all channels */
+ for (i=0; i<iface->chan_count; i++) {
+ struct keywest_chan* chan = &iface->channels[i];
+ if (i2c_get_adapdata(&chan->adapter) == NULL)
+ continue;
+ rc = i2c_del_adapter(&chan->adapter);
+ i2c_set_adapdata(&chan->adapter, NULL);
+ /* We aren't that prepared to deal with this... */
+ if (rc)
+ printk("i2c-keywest.c: i2c_del_adapter failed, that's bad !\n");
+ }
+ iounmap((void *)iface->base);
+ dev_set_drvdata(dev, NULL);
+ kfree(iface);
+
+ return 0;
+}
+
+static int
+create_iface_macio(struct macio_dev* dev, const struct of_match *match)
+{
+ return create_iface(dev->ofdev.node, &dev->ofdev.dev);
+}
+
+static int
+dispose_iface_macio(struct macio_dev* dev)
+{
+ return dispose_iface(&dev->ofdev.dev);
+}
+
+static int
+create_iface_of_platform(struct of_device* dev, const struct of_match *match)
+{
+ return create_iface(dev->node, &dev->dev);
+}
+
+static int
+dispose_iface_of_platform(struct of_device* dev)
+{
+ return dispose_iface(&dev->dev);
+}
+
+static struct of_match i2c_keywest_match[] =
+{
+ {
+ .name = OF_ANY_MATCH,
+ .type = "i2c",
+ .compatible = "keywest"
+ },
+ {},
+};
+
+static struct macio_driver i2c_keywest_macio_driver =
+{
+ .name = "i2c-keywest",
+ .match_table = i2c_keywest_match,
+ .probe = create_iface_macio,
+ .remove = dispose_iface_macio
+};
+
+static struct of_platform_driver i2c_keywest_of_platform_driver =
+{
+ .name = "i2c-keywest",
+ .match_table = i2c_keywest_match,
+ .probe = create_iface_of_platform,
+ .remove = dispose_iface_of_platform
+};
+
+static int __init
+i2c_keywest_init(void)
+{
+ macio_register_driver(&i2c_keywest_macio_driver);
+ of_register_driver(&i2c_keywest_of_platform_driver);
+
+ return 0;
+}
+
+static void __exit
+i2c_keywest_cleanup(void)
+{
+ macio_unregister_driver(&i2c_keywest_macio_driver);
+ of_unregister_driver(&i2c_keywest_of_platform_driver);
+}
+
+module_init(i2c_keywest_init);
+module_exit(i2c_keywest_cleanup);
--- /dev/null
+#ifndef __I2C_KEYWEST_H__
+#define __I2C_KEYWEST_H__
+
+/* The Tumbler audio equalizer can be really slow sometimes */
+#define POLL_TIMEOUT (2*HZ)
+
+/* Register indices */
+typedef enum {
+ reg_mode = 0,
+ reg_control,
+ reg_status,
+ reg_isr,
+ reg_ier,
+ reg_addr,
+ reg_subaddr,
+ reg_data
+} reg_t;
+
+
+/* Mode register */
+#define KW_I2C_MODE_100KHZ 0x00
+#define KW_I2C_MODE_50KHZ 0x01
+#define KW_I2C_MODE_25KHZ 0x02
+#define KW_I2C_MODE_DUMB 0x00
+#define KW_I2C_MODE_STANDARD 0x04
+#define KW_I2C_MODE_STANDARDSUB 0x08
+#define KW_I2C_MODE_COMBINED 0x0C
+#define KW_I2C_MODE_MODE_MASK 0x0C
+#define KW_I2C_MODE_CHAN_MASK 0xF0
+
+/* Control register */
+#define KW_I2C_CTL_AAK 0x01
+#define KW_I2C_CTL_XADDR 0x02
+#define KW_I2C_CTL_STOP 0x04
+#define KW_I2C_CTL_START 0x08
+
+/* Status register */
+#define KW_I2C_STAT_BUSY 0x01
+#define KW_I2C_STAT_LAST_AAK 0x02
+#define KW_I2C_STAT_LAST_RW 0x04
+#define KW_I2C_STAT_SDA 0x08
+#define KW_I2C_STAT_SCL 0x10
+
+/* IER & ISR registers */
+#define KW_I2C_IRQ_DATA 0x01
+#define KW_I2C_IRQ_ADDR 0x02
+#define KW_I2C_IRQ_STOP 0x04
+#define KW_I2C_IRQ_START 0x08
+#define KW_I2C_IRQ_MASK 0x0F
+
+/* Physical interface */
+struct keywest_iface
+{
+ unsigned long base;
+ unsigned bsteps;
+ int irq;
+ struct semaphore sem;
+ spinlock_t lock;
+ struct keywest_chan* channels;
+ unsigned chan_count;
+ u8 cur_mode;
+ char read_write;
+ u8* data;
+ unsigned datalen;
+ int state;
+ int result;
+ int stopretry;
+ struct timer_list timeout_timer;
+ struct completion complete;
+};
+
+enum {
+ state_idle,
+ state_addr,
+ state_read,
+ state_write,
+ state_stop,
+ state_dead
+};
+
+/* Channel on an interface */
+struct keywest_chan
+{
+ struct i2c_adapter adapter;
+ struct keywest_iface* iface;
+ unsigned chan_no;
+};
+
+/* Register access */
+
+static inline u8 __read_reg(struct keywest_iface *iface, reg_t reg)
+{
+ return in_8(((volatile u8 *)iface->base)
+ + (((unsigned)reg) << iface->bsteps));
+}
+
+static inline void __write_reg(struct keywest_iface *iface, reg_t reg, u8 val)
+{
+ out_8(((volatile u8 *)iface->base)
+ + (((unsigned)reg) << iface->bsteps), val);
+ (void)__read_reg(iface, reg);
+ udelay(10);
+}
+
+#define write_reg(reg, val) __write_reg(iface, reg, val)
+#define read_reg(reg) __read_reg(iface, reg)
+
+
+
+#endif /* __I2C_KEYWEST_H__ */
--- /dev/null
+/*
+ * Embedded Planet RPX Lite MPC8xx CPM I2C interface.
+ * Copyright (c) 1999 Dan Malek (dmalek@jlc.net).
+ *
+ * moved into proper i2c interface;
+ * Brad Parker (brad@heeltoe.com)
+ *
+ * RPX lite specific parts of the i2c interface
+ * Update: There actually isn't anything RPXLite-specific about this module.
+ * This should work for most any 8xx board. The console messages have been
+ * changed to eliminate RPXLite references.
+ */
+
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/stddef.h>
+#include <linux/parport.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-8xx.h>
+#include <asm/mpc8xx.h>
+#include <asm/commproc.h>
+
+
+static void
+rpx_iic_init(struct i2c_algo_8xx_data *data)
+{
+ volatile cpm8xx_t *cp;
+ volatile immap_t *immap;
+
+ cp = cpmp; /* Get pointer to Communication Processor */
+ immap = (immap_t *)IMAP_ADDR; /* and to internal registers */
+
+ data->iip = (iic_t *)&cp->cp_dparam[PROFF_IIC];
+
+ /* Check for and use a microcode relocation patch.
+ */
+ if ((data->reloc = data->iip->iic_rpbase))
+ data->iip = (iic_t *)&cp->cp_dpmem[data->iip->iic_rpbase];
+
+ data->i2c = (i2c8xx_t *)&(immap->im_i2c);
+ data->cp = cp;
+
+ /* Initialize Port B IIC pins.
+ */
+ cp->cp_pbpar |= 0x00000030;
+ cp->cp_pbdir |= 0x00000030;
+ cp->cp_pbodr |= 0x00000030;
+
+ /* Allocate space for two transmit and two receive buffer
+ * descriptors in the DP ram.
+ */
+ data->dp_addr = m8xx_cpm_dpalloc(sizeof(cbd_t) * 4);
+
+ /* ptr to i2c area */
+ data->i2c = (i2c8xx_t *)&(((immap_t *)IMAP_ADDR)->im_i2c);
+}
+
+static int rpx_install_isr(int irq, void (*func)(void *, void *), void *data)
+{
+ /* install interrupt handler */
+ cpm_install_handler(irq, (void (*)(void *, struct pt_regs *)) func, data);
+
+ return 0;
+}
+
+static struct i2c_algo_8xx_data rpx_data = {
+ .setisr = rpx_install_isr
+};
+
+static struct i2c_adapter rpx_ops = {
+ .owner = THIS_MODULE,
+ .name = "m8xx",
+ .id = I2C_HW_MPC8XX_EPON,
+ .algo_data = &rpx_data,
+};
+
+int __init i2c_rpx_init(void)
+{
+ printk("i2c-rpx.o: i2c MPC8xx module version %s (%s)\n", I2C_VERSION, I2C_DATE);
+
+ /* reset hardware to sane state */
+ rpx_iic_init(&rpx_data);
+
+ if (i2c_8xx_add_bus(&rpx_ops) < 0) {
+ printk("i2c-rpx: Unable to register with I2C\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+void __exit i2c_rpx_exit(void)
+{
+ i2c_8xx_del_bus(&rpx_ops);
+}
+
+MODULE_AUTHOR("Dan Malek <dmalek@jlc.net>");
+MODULE_DESCRIPTION("I2C-Bus adapter routines for MPC8xx boards");
+
+module_init(i2c_rpx_init);
+module_exit(i2c_rpx_exit);
+++ /dev/null
-/*
- -------------------------------------------------------------------------
- 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 <kmalkki@cc.hut.fi> and even
- Frodo Looijaard <frodol@dds.nl> */
-
-#include <linux/kernel.h>
-#include <linux/ioport.h>
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <asm/irq.h>
-#include <asm/io.h>
-
-#include <linux/i2c.h>
-#include <linux/i2c-algo-ite.h>
-#include <linux/i2c-adap-ite.h>
-#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 = 0;
-static int irq = 0;
-static int clock = 0;
-static int own = 0;
-
-static int i2c_debug=0;
-static struct iic_ite gpi;
-static wait_queue_head_t iic_wait;
-static int iic_pending;
-
-/* ----- global defines ----------------------------------------------- */
-#define DEB(x) if (i2c_debug>=1) x
-#define DEB2(x) if (i2c_debug>=2) x
-#define DEB3(x) if (i2c_debug>=3) x
-#define DEBE(x) x /* error messages */
-
-
-/* ----- local functions ---------------------------------------------- */
-
-static void iic_ite_setiic(void *data, int ctl, short val)
-{
- unsigned long j = jiffies + 10;
-
- DEB3(printk(" Write 0x%02x to 0x%x\n",(unsigned short)val, ctl&0xff));
- DEB3({while (time_before(jiffies, j)) schedule();})
- outw(val,ctl);
-}
-
-static short iic_ite_getiic(void *data, int ctl)
-{
- short val;
-
- val = inw(ctl);
- DEB3(printk("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);
-}
-
-
-#if 0
-static void iic_ite_sleep(unsigned long timeout)
-{
- schedule_timeout( timeout * HZ);
-}
-#endif
-
-
-/* Put this process to sleep. We will wake up when the
- * IIC controller interrupts.
- */
-static void iic_ite_waitforpin(void) {
-
- int timeout = 2;
-
- /* 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) {
- cli();
- if (iic_pending == 0) {
- interruptible_sleep_on_timeout(&iic_wait, timeout*HZ );
- } else
- iic_pending = 0;
- sti();
- } else {
- udelay(100);
- }
-}
-
-
-static void iic_ite_handler(int this_irq, void *dev_id, struct pt_regs *regs)
-{
-
- iic_pending = 1;
-
- DEB2(printk("iic_ite_handler: in interrupt handler\n"));
- wake_up_interruptible(&iic_wait);
-}
-
-
-/* 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,
- .dev = {
- .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);
- 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 <www.mvista.com>");
-MODULE_DESCRIPTION("I2C-Bus adapter routines for ITE IIC bus adapter");
-MODULE_LICENSE("GPL");
-
-MODULE_PARM(base, "i");
-MODULE_PARM(irq, "i");
-MODULE_PARM(clock, "i");
-MODULE_PARM(own, "i");
-MODULE_PARM(i2c_debug,"i");
-
-
-/* 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);
+++ /dev/null
-
-/*
- * linux/drivers/i2c/i2c-frodo.c
- *
- * Author: Abraham van der Merwe <abraham@2d3d.co.za>
- *
- * An I2C adapter driver for the 2d3D, Inc. StrongARM SA-1110
- * Development board (Frodo).
- *
- * This source code 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 <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/i2c.h>
-#include <linux/i2c-algo-bit.h>
-#include <asm/hardware.h>
-
-
-static void frodo_setsda (void *data,int state)
-{
- if (state)
- FRODO_CPLD_I2C |= FRODO_I2C_SDA_OUT;
- else
- FRODO_CPLD_I2C &= ~FRODO_I2C_SDA_OUT;
-}
-
-static void frodo_setscl (void *data,int state)
-{
- if (state)
- FRODO_CPLD_I2C |= FRODO_I2C_SCL_OUT;
- else
- FRODO_CPLD_I2C &= ~FRODO_I2C_SCL_OUT;
-}
-
-static int frodo_getsda (void *data)
-{
- return ((FRODO_CPLD_I2C & FRODO_I2C_SDA_IN) != 0);
-}
-
-static int frodo_getscl (void *data)
-{
- return ((FRODO_CPLD_I2C & FRODO_I2C_SCL_IN) != 0);
-}
-
-static struct i2c_algo_bit_data bit_frodo_data = {
- .setsda = frodo_setsda,
- .setscl = frodo_setscl,
- .getsda = frodo_getsda,
- .getscl = frodo_getscl,
- .udelay = 80,
- .mdelay = 80,
- .timeout = HZ
-};
-
-static struct i2c_adapter frodo_ops = {
- .owner = THIS_MODULE,
- .id = I2C_HW_B_FRODO,
- .algo_data = &bit_frodo_data,
- .dev = {
- .name = "Frodo adapter driver",
- },
-};
-
-static int __init i2c_frodo_init (void)
-{
- return i2c_bit_add_bus(&frodo_ops);
-}
-
-static void __exit i2c_frodo_exit (void)
-{
- i2c_bit_del_bus(&frodo_ops);
-}
-
-MODULE_AUTHOR ("Abraham van der Merwe <abraham@2d3d.co.za>");
-MODULE_DESCRIPTION ("I2C-Bus adapter routines for Frodo");
-MODULE_LICENSE ("GPL");
-
-module_init (i2c_frodo_init);
-module_exit (i2c_frodo_exit);
-
+++ /dev/null
-/*
- * drivers/i2c/i2c-ibm_iic.c
- *
- * Support for the IIC peripheral on IBM PPC 4xx
- *
- * Copyright (c) 2003 Zultys Technologies.
- * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
- *
- * Based on original work by
- * Ian DaSilva <idasilva@mvista.com>
- * Armin Kuster <akuster@mvista.com>
- * Matt Porter <mporter@mvista.com>
- *
- * Copyright 2000-2003 MontaVista Software Inc.
- *
- * Original driver version was highly leveraged from i2c-elektor.c
- *
- * Copyright 1995-97 Simon G. Vogl
- * 1998-99 Hans Berglund
- *
- * With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi>
- * and even Frodo Looijaard <frodol@dds.nl>
- *
- * 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 <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <asm/irq.h>
-#include <asm/io.h>
-#include <linux/i2c.h>
-#include <linux/i2c-id.h>
-#include <asm/ocp.h>
-#include <asm/ibm4xx.h>
-
-#include "i2c-ibm_iic.h"
-
-#define DRIVER_VERSION "2.0"
-
-MODULE_DESCRIPTION("IBM IIC driver v" DRIVER_VERSION);
-MODULE_LICENSE("GPL");
-
-static int iic_scan = 0;
-MODULE_PARM(iic_scan, "i");
-MODULE_PARM_DESC(iic_scan, "Scan for active chips on the bus");
-
-static int iic_force_poll = 0;
-MODULE_PARM(iic_force_poll, "i");
-MODULE_PARM_DESC(iic_force_poll, "Force polling mode");
-
-static int iic_force_fast = 0;
-MODULE_PARM(iic_force_fast, "i");
-MODULE_PARM_DESC(iic_fast_poll, "Force fast mode (400 kHz)");
-
-#define DBG_LEVEL 0
-
-#ifdef DBG
-#undef DBG
-#endif
-
-#ifdef DBG2
-#undef DBG2
-#endif
-
-#if DBG_LEVEL > 0
-# define DBG(x...) printk(KERN_DEBUG "ibm-iic" ##x)
-#else
-# define DBG(x...) ((void)0)
-#endif
-#if DBG_LEVEL > 1
-# define DBG2(x...) DBG( ##x )
-#else
-# define DBG2(x...) ((void)0)
-#endif
-#if DBG_LEVEL > 2
-static void dump_iic_regs(const char* header, struct ibm_iic_private* dev)
-{
- volatile struct iic_regs *iic = dev->vaddr;
- printk(KERN_DEBUG "ibm-iic%d: %s\n", dev->idx, header);
- printk(KERN_DEBUG " cntl = 0x%02x, mdcntl = 0x%02x\n"
- 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->xtcntlss), in_8(&iic->directcntl));
-}
-# define DUMP_REGS(h,dev) dump_iic_regs((h),(dev))
-#else
-# define DUMP_REGS(h,dev) ((void)0)
-#endif
-
-/* Enable/disable interrupt generation */
-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.
- */
-static void iic_dev_init(struct ibm_iic_private* dev)
-{
- volatile struct iic_regs *iic = dev->vaddr;
-
- DBG("%d: init\n", dev->idx);
-
- /* Clear master address */
- out_8(&iic->lmadr, 0);
- out_8(&iic->hmadr, 0);
-
- /* Clear slave address */
- out_8(&iic->lsadr, 0);
- out_8(&iic->hsadr, 0);
-
- /* Clear status & extended status */
- out_8(&iic->sts, STS_SCMP | STS_IRQA);
- out_8(&iic->extsts, EXTSTS_IRQP | EXTSTS_IRQD | EXTSTS_LA
- | EXTSTS_ICT | EXTSTS_XFRA);
-
- /* Set clock divider */
- out_8(&iic->clkdiv, dev->clckdiv);
-
- /* Clear transfer count */
- out_8(&iic->xfrcnt, 0);
-
- /* Clear extended control and status */
- out_8(&iic->xtcntlss, XTCNTLSS_SRC | XTCNTLSS_SRS | XTCNTLSS_SWC
- | XTCNTLSS_SWS);
-
- /* Clear control register */
- out_8(&iic->cntl, 0);
-
- /* Enable interrupts if possible */
- iic_interrupt_mode(dev, dev->irq >= 0);
-
- /* Set mode control */
- out_8(&iic->mdcntl, MDCNTL_FMDB | MDCNTL_EINT | MDCNTL_EUBS
- | (dev->fast_mode ? MDCNTL_FSM : 0));
-
- DUMP_REGS("iic_init", dev);
-}
-
-/*
- * Reset IIC interface
- */
-static void iic_dev_reset(struct ibm_iic_private* dev)
-{
- volatile struct iic_regs *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);
- 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);
-
- /* 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);
-}
-
-/*
- * IIC interrupt handler
- */
-static irqreturn_t iic_handler(int irq, void *dev_id, struct pt_regs *regs)
-{
- struct ibm_iic_private* dev = (struct ibm_iic_private*)dev_id;
- volatile struct iic_regs* iic = dev->vaddr;
-
- 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;
-}
-
-/*
- * Get master transfer result and clear errors if any.
- * Returns the number of actually transferred bytes or error (<0)
- */
-static int iic_xfer_result(struct ibm_iic_private* dev)
-{
- volatile struct iic_regs *iic = dev->vaddr;
-
- if (unlikely(in_8(&iic->sts) & STS_ERR)){
- 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 |
- 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
- * state, the only way out - soft reset.
- */
- if ((in_8(&iic->extsts) & EXTSTS_BCS_MASK) != EXTSTS_BCS_FREE){
- DBG("%d: bus is stuck, resetting\n", dev->idx);
- iic_dev_reset(dev);
- }
- return -EREMOTEIO;
- }
- else
- return in_8(&iic->xfrcnt) & XFRCNT_MTC_MASK;
-}
-
-/*
- * Try to abort active transfer.
- */
-static void iic_abort_xfer(struct ibm_iic_private* dev)
-{
- volatile struct iic_regs *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)
- */
- x = jiffies + 2;
- while ((in_8(&iic->extsts) & EXTSTS_BCS_MASK) != EXTSTS_BCS_FREE){
- if (time_after(jiffies, x)){
- DBG("%d: abort timeout, resetting...\n", dev->idx);
- iic_dev_reset(dev);
- return;
- }
- schedule();
- }
-
- /* Just to clear errors */
- iic_xfer_result(dev);
-}
-
-/*
- * Wait for master transfer to complete.
- * It puts current process to sleep until we get interrupt or timeout expires.
- * Returns the number of transferred bytes or error (<0)
- */
-static int iic_wait_for_tc(struct ibm_iic_private* dev){
-
- volatile struct iic_regs *iic = dev->vaddr;
- int ret = 0;
-
- if (dev->irq >= 0){
- /* Interrupt mode */
- wait_queue_t wait;
- init_waitqueue_entry(&wait, current);
-
- add_wait_queue(&dev->wq, &wait);
- set_current_state(TASK_INTERRUPTIBLE);
- if (in_8(&iic->sts) & STS_PT)
- schedule_timeout(dev->adap.timeout * HZ);
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&dev->wq, &wait);
-
- if (unlikely(signal_pending(current))){
- DBG("%d: wait interrupted\n", dev->idx);
- ret = -ERESTARTSYS;
- } else if (unlikely(in_8(&iic->sts) & STS_PT)){
- DBG("%d: wait timeout\n", dev->idx);
- ret = -ETIMEDOUT;
- }
- }
- 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,
- int combined_xfer)
-{
- volatile struct iic_regs *iic = dev->vaddr;
- char* buf = pm->buf;
- int i, j, loops, ret = 0;
- int len = pm->len;
-
- 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((volatile u8*)&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",
- 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;
- }
-
- if (cntl & CNTL_RW)
- for (j = 0; j < count; ++j)
- *buf++ = in_8((volatile u8*)&iic->mdbuf);
- }
-
- return ret > 0 ? 0 : ret;
-}
-
-/*
- * Set target slave address for master transfer
- */
-static inline void iic_address(struct ibm_iic_private* dev, struct i2c_msg* msg)
-{
- volatile struct iic_regs *iic = dev->vaddr;
- u16 addr = msg->addr;
-
- 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);
- out_8(&iic->hmadr, 0xf0 | ((addr >> 7) & 0x06));
- }
- else {
- out_8(&iic->cntl, 0);
- out_8(&iic->lmadr, addr << 1);
- }
-}
-
-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,
- const struct i2c_msg* p2)
-{
- return (p1->addr != p2->addr)
- || ((p1->flags & I2C_M_TEN) != (p2->flags & I2C_M_TEN));
-}
-
-/*
- * 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)
-{
- struct ibm_iic_private* dev = (struct ibm_iic_private*)(i2c_get_adapdata(adap));
- volatile struct iic_regs *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,
- 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)){
- DBG("%d: invalid len %d in msg[%d]\n", dev->idx,
- msgs[i].len, i);
- return -EINVAL;
- }
- if (unlikely(iic_address_neq(&msgs[0], &msgs[i]))){
- DBG("%d: invalid addr in msg[%d]\n", dev->idx, i);
- 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
- * 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);
-
- return ret < 0 ? ret : num;
-}
-
-static u32 iic_func(struct i2c_adapter *adap)
-{
- return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR;
-}
-
-static struct i2c_algorithm iic_algo = {
- .name = "IBM IIC algorithm",
- .id = I2C_ALGO_OCP,
- .master_xfer = iic_xfer,
- .smbus_xfer = NULL,
- .slave_send = NULL,
- .slave_recv = NULL,
- .algo_control = NULL,
- .functionality = iic_func
-};
-
-/*
- * Scan bus for valid 7-bit addresses (ie things that ACK on 1 byte read)
- * We only scan range [0x08 - 0x77], all other addresses are reserved anyway
- */
-static void __devinit iic_scan_bus(struct ibm_iic_private* dev)
-{
- int found = 0;
- char dummy;
- struct i2c_msg msg = {
- .buf = &dummy,
- .len = sizeof(dummy),
- .flags = I2C_M_RD
- };
-
- printk(KERN_INFO "ibm-iic%d: scanning bus...\n" KERN_INFO, dev->idx);
-
- for (msg.addr = 8; msg.addr < 0x78; ++msg.addr)
- if (iic_xfer(&dev->adap, &msg, 1) == 1){
- ++found;
- printk(" 0x%02x", msg.addr);
- }
-
- printk("%sibm-iic%d: %d device(s) detected\n",
- found ? "\n" KERN_INFO : "", dev->idx, found);
-}
-
-/*
- * Calculates IICx_CLCKDIV value for a specific OPB clock frequency
- */
-static inline u8 iic_clckdiv(unsigned int opb)
-{
- /* Compatibility kludge, should go away after all cards
- * are fixed to fill correct value for opbfreq.
- * Previous driver version used hardcoded divider value 4,
- * it corresponds to OPB frequency from the range (40, 50] MHz
- */
- if (!opb){
- printk(KERN_WARNING "ibm-iic: using compatibility value for OPB freq,"
- " fix your board specific setup\n");
- opb = 50000000;
- }
-
- /* Convert to MHz */
- opb /= 1000000;
-
- if (opb < 20 || opb > 150){
- printk(KERN_CRIT "ibm-iic: invalid OPB clock frequency %u MHz\n",
- opb);
- opb = opb < 20 ? 20 : 150;
- }
- return (u8)((opb + 9) / 10 - 1);
-}
-
-/*
- * Register single IIC interface
- */
-static int __devinit iic_probe(struct ocp_device *ocp){
-
- struct ibm_iic_private* dev;
- struct i2c_adapter* adap;
- int ret;
- bd_t* bd = (bd_t*)&__res;
-
- if (!(dev = kmalloc(sizeof(*dev), GFP_KERNEL))){
- printk(KERN_CRIT "ibm-iic: failed to allocate device data\n");
- return -ENOMEM;
- }
-
- memset(dev, 0, sizeof(*dev));
- dev->idx = ocp->num;
- ocp_set_drvdata(ocp, dev);
-
- if (!(dev->vaddr = ioremap(ocp->paddr, sizeof(struct iic_regs)))){
- printk(KERN_CRIT "ibm-iic%d: failed to ioremap device registers\n",
- dev->idx);
- ret = -ENXIO;
- goto fail2;
- }
-
- init_waitqueue_head(&dev->wq);
-
- dev->irq = iic_force_poll ? -1 : ocp->irq;
- if (dev->irq >= 0){
- /* Disable interrupts until we finish intialization,
- assumes level-sensitive IRQ setup...
- */
- 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",
- dev->idx, dev->irq);
- /* Fallback to the polling mode */
- dev->irq = -1;
- }
- }
-
- if (dev->irq < 0)
- printk(KERN_WARNING "ibm-iic%d: using polling mode\n",
- dev->idx);
-
- /* Board specific settings */
- BUG_ON(dev->idx >= sizeof(bd->bi_iic_fast) / sizeof(bd->bi_iic_fast[0]));
- dev->fast_mode = iic_force_fast ? 1 : bd->bi_iic_fast[dev->idx];
-
- /* clckdiv is the same for *all* IIC interfaces,
- * but I'd rather make a copy than introduce another global. --ebs
- */
- dev->clckdiv = iic_clckdiv(bd->bi_opb_busfreq);
- DBG("%d: clckdiv = %d\n", dev->idx, dev->clckdiv);
-
- /* Initialize IIC interface */
- iic_dev_init(dev);
-
- /* Register it with i2c layer */
- adap = &dev->adap;
- strcpy(adap->dev.name, "IBM IIC");
- i2c_set_adapdata(adap, dev);
- adap->id = I2C_HW_OCP | iic_algo.id;
- adap->algo = &iic_algo;
- adap->client_register = NULL;
- adap->client_unregister = NULL;
- adap->timeout = 1;
- adap->retries = 1;
-
- if ((ret = i2c_add_adapter(adap)) != 0){
- printk(KERN_CRIT "ibm-iic%d: failed to register i2c adapter\n",
- 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)");
-
- /* Scan bus if requested by user */
- if (iic_scan)
- iic_scan_bus(dev);
-
- return 0;
-
-fail:
- if (dev->irq >= 0){
- iic_interrupt_mode(dev, 0);
- free_irq(dev->irq, dev);
- }
-
- iounmap((void*)dev->vaddr);
-fail2:
- ocp_set_drvdata(ocp, 0);
- kfree(dev);
- return ret;
-}
-
-/*
- * Cleanup initialized IIC interface
- */
-static void __devexit iic_remove(struct ocp_device *ocp)
-{
- struct ibm_iic_private* dev = (struct ibm_iic_private*)ocp_get_drvdata(ocp);
- BUG_ON(dev == NULL);
- if (i2c_del_adapter(&dev->adap)){
- printk(KERN_CRIT "ibm-iic%d: failed to delete i2c adapter :(\n",
- dev->idx);
- /* That's *very* bad, just shutdown IRQ ... */
- if (dev->irq >= 0){
- iic_interrupt_mode(dev, 0);
- free_irq(dev->irq, dev);
- dev->irq = -1;
- }
- } else {
- if (dev->irq >= 0){
- iic_interrupt_mode(dev, 0);
- free_irq(dev->irq, dev);
- }
- iounmap((void*)dev->vaddr);
- kfree(dev);
- }
-}
-
-static struct ocp_device_id ibm_iic_ids[] __devinitdata =
-{
- { .vendor = OCP_VENDOR_IBM, .device = OCP_FUNC_IIC },
- { .vendor = OCP_VENDOR_INVALID }
-};
-
-MODULE_DEVICE_TABLE(ocp, ibm_iic_ids);
-
-static struct ocp_driver ibm_iic_driver =
-{
- .name = "ocp_iic",
- .id_table = ibm_iic_ids,
- .probe = iic_probe,
- .remove = __devexit_p(iic_remove),
-#if defined(CONFIG_PM)
- .suspend = NULL,
- .resume = NULL,
-#endif
-};
-
-static int __init iic_init(void)
-{
- printk(KERN_INFO "IBM IIC driver v" DRIVER_VERSION "\n");
- return ocp_module_init(&ibm_iic_driver);
-}
-
-static void __exit iic_exit(void)
-{
- ocp_unregister_driver(&ibm_iic_driver);
-}
-
-module_init(iic_init);
-module_exit(iic_exit);
+++ /dev/null
-/*
- * drivers/i2c/i2c-ibm_iic.h
- *
- * Support for the IIC peripheral on IBM PPC 4xx
- *
- * Copyright (c) 2003 Zultys Technologies.
- * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
- *
- * Based on original work by
- * Ian DaSilva <idasilva@mvista.com>
- * Armin Kuster <akuster@mvista.com>
- * Matt Porter <mporter@mvista.com>
- *
- * Copyright 2000-2003 MontaVista Software Inc.
- *
- * 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.
- *
- */
-#ifndef __I2C_IBM_IIC_H_
-#define __I2C_IBM_IIC_H_
-
-#include <linux/config.h>
-#include <linux/i2c.h>
-
-struct iic_regs {
- u16 mdbuf;
- u16 sbbuf;
- u8 lmadr;
- u8 hmadr;
- u8 cntl;
- u8 mdcntl;
- u8 sts;
- u8 extsts;
- u8 lsadr;
- u8 hsadr;
- u8 clkdiv;
- u8 intmsk;
- u8 xfrcnt;
- u8 xtcntlss;
- u8 directcntl;
-};
-
-struct ibm_iic_private {
- struct i2c_adapter adap;
- volatile struct iic_regs *vaddr;
- wait_queue_head_t wq;
- int idx;
- int irq;
- int fast_mode;
- u8 clckdiv;
-};
-
-/* IICx_CNTL register */
-#define CNTL_HMT 0x80
-#define CNTL_AMD 0x40
-#define CNTL_TCT_MASK 0x30
-#define CNTL_TCT_SHIFT 4
-#define CNTL_RPST 0x08
-#define CNTL_CHT 0x04
-#define CNTL_RW 0x02
-#define CNTL_PT 0x01
-
-/* IICx_MDCNTL register */
-#define MDCNTL_FSDB 0x80
-#define MDCNTL_FMDB 0x40
-#define MDCNTL_EGC 0x20
-#define MDCNTL_FSM 0x10
-#define MDCNTL_ESM 0x08
-#define MDCNTL_EINT 0x04
-#define MDCNTL_EUBS 0x02
-#define MDCNTL_HSCL 0x01
-
-/* IICx_STS register */
-#define STS_SSS 0x80
-#define STS_SLPR 0x40
-#define STS_MDBS 0x20
-#define STS_MDBF 0x10
-#define STS_SCMP 0x08
-#define STS_ERR 0x04
-#define STS_IRQA 0x02
-#define STS_PT 0x01
-
-/* IICx_EXTSTS register */
-#define EXTSTS_IRQP 0x80
-#define EXTSTS_BCS_MASK 0x70
-#define EXTSTS_BCS_FREE 0x40
-#define EXTSTS_IRQD 0x08
-#define EXTSTS_LA 0x04
-#define EXTSTS_ICT 0x02
-#define EXTSTS_XFRA 0x01
-
-/* IICx_INTRMSK register */
-#define INTRMSK_EIRC 0x80
-#define INTRMSK_EIRS 0x40
-#define INTRMSK_EIWC 0x20
-#define INTRMSK_EIWS 0x10
-#define INTRMSK_EIHE 0x08
-#define INTRMSK_EIIC 0x04
-#define INTRMSK_EITA 0x02
-#define INTRMSK_EIMTC 0x01
-
-/* IICx_XFRCNT register */
-#define XFRCNT_MTC_MASK 0x07
-
-/* IICx_XTCNTLSS register */
-#define XTCNTLSS_SRC 0x80
-#define XTCNTLSS_SRS 0x40
-#define XTCNTLSS_SWC 0x20
-#define XTCNTLSS_SWS 0x10
-#define XTCNTLSS_SRST 0x01
-
-/* IICx_DIRECTCNTL register */
-#define DIRCNTL_SDAC 0x08
-#define DIRCNTL_SCC 0x04
-#define DIRCNTL_MSDA 0x02
-#define DIRCNTL_MSC 0x01
-
-/* Check if we really control the I2C bus and bus is free */
-#define DIRCTNL_FREE(v) (((v) & 0x0f) == 0x0f)
-
-#endif /* __I2C_IBM_IIC_H_ */
+++ /dev/null
-/* ------------------------------------------------------------------------- */
-/* i2c-iop3xx.c i2c driver algorithms for Intel XScale IOP3xx */
-/* ------------------------------------------------------------------------- */
-/* Copyright (C) 2003 Peter Milne, D-TACQ Solutions Ltd
- * <Peter dot Milne at D hyphen TACQ dot com>
-
- 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, version 2.
-
-
- 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 acknowledgements to i2c-algo-ibm_ocp.c by
- Ian DaSilva, MontaVista Software, Inc. idasilva@mvista.com
-
- And i2c-algo-pcf.c, which was created by Simon G. Vogl and Hans Berglund:
-
- Copyright (C) 1995-1997 Simon G. Vogl, 1998-2000 Hans Berglund
-
- And which acknowledged Kyösti Mälkki <kmalkki@cc.hut.fi>,
- Frodo Looijaard <frodol@dds.nl>, Martin Bailey<mbailey@littlefeet-inc.com>
-
- ---------------------------------------------------------------------------*/
-
-
-#include <linux/interrupt.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/i2c.h>
-
-
-#include <asm/arch-iop3xx/iop321.h>
-#include <asm/arch-iop3xx/iop321-irqs.h>
-#include "i2c-iop3xx.h"
-
-
-/* ----- global defines ----------------------------------------------- */
-#define PASSERT(x) do { if (!(x) ) \
- printk(KERN_CRIT "PASSERT %s in %s:%d\n", #x, __FILE__, __LINE__ );\
- } while (0)
-
-
-/* ----- global variables --------------------------------------------- */
-
-
-static inline unsigned char iic_cook_addr(struct i2c_msg *msg)
-{
- unsigned char addr;
-
- addr = (msg->addr << 1);
-
- if (msg->flags & I2C_M_RD)
- addr |= 1;
-
- /* PGM: what is M_REV_DIR_ADDR - do we need it ?? */
- if (msg->flags & I2C_M_REV_DIR_ADDR)
- addr ^= 1;
-
- return addr;
-}
-
-
-static inline void iop3xx_adap_reset(struct i2c_algo_iop3xx_data *iop3xx_adap)
-{
- /* Follows devman 9.3 */
- *iop3xx_adap->biu->CR = IOP321_ICR_UNIT_RESET;
- *iop3xx_adap->biu->SR = IOP321_ISR_CLEARBITS;
- *iop3xx_adap->biu->CR = 0;
-}
-
-static inline void iop3xx_adap_set_slave_addr(struct i2c_algo_iop3xx_data *iop3xx_adap)
-{
- *iop3xx_adap->biu->SAR = MYSAR;
-}
-
-static inline void iop3xx_adap_enable(struct i2c_algo_iop3xx_data *iop3xx_adap)
-{
- u32 cr = IOP321_ICR_GCD|IOP321_ICR_SCLEN|IOP321_ICR_UE;
-
- /* NB SR bits not same position as CR IE bits :-( */
- iop3xx_adap->biu->SR_enabled =
- IOP321_ISR_ALD | IOP321_ISR_BERRD |
- IOP321_ISR_RXFULL | IOP321_ISR_TXEMPTY;
-
- cr |= IOP321_ICR_ALDIE | IOP321_ICR_BERRIE |
- IOP321_ICR_RXFULLIE | IOP321_ICR_TXEMPTYIE;
-
- *iop3xx_adap->biu->CR = cr;
-}
-
-static void iop3xx_adap_transaction_cleanup(struct i2c_algo_iop3xx_data *iop3xx_adap)
-{
- unsigned cr = *iop3xx_adap->biu->CR;
-
- cr &= ~(IOP321_ICR_MSTART | IOP321_ICR_TBYTE |
- IOP321_ICR_MSTOP | IOP321_ICR_SCLEN);
- *iop3xx_adap->biu->CR = cr;
-}
-
-static void iop3xx_adap_final_cleanup(struct i2c_algo_iop3xx_data *iop3xx_adap)
-{
- unsigned cr = *iop3xx_adap->biu->CR;
-
- cr &= ~(IOP321_ICR_ALDIE | IOP321_ICR_BERRIE |
- IOP321_ICR_RXFULLIE | IOP321_ICR_TXEMPTYIE);
- iop3xx_adap->biu->SR_enabled = 0;
- *iop3xx_adap->biu->CR = cr;
-}
-
-/*
- * NB: the handler has to clear the source of the interrupt!
- * Then it passes the SR flags of interest to BH via adap data
- */
-static void iop3xx_i2c_handler(int this_irq,
- void *dev_id,
- struct pt_regs *regs)
-{
- struct i2c_algo_iop3xx_data *iop3xx_adap = dev_id;
-
- u32 sr = *iop3xx_adap->biu->SR;
-
- if ((sr &= iop3xx_adap->biu->SR_enabled)) {
- *iop3xx_adap->biu->SR = sr;
- iop3xx_adap->biu->SR_received |= sr;
- wake_up_interruptible(&iop3xx_adap->waitq);
- }
-}
-
-/* check all error conditions, clear them , report most important */
-static int iop3xx_adap_error(u32 sr)
-{
- int rc = 0;
-
- if ((sr&IOP321_ISR_BERRD)) {
- if ( !rc ) rc = -I2C_ERR_BERR;
- }
- if ((sr&IOP321_ISR_ALD)) {
- if ( !rc ) rc = -I2C_ERR_ALD;
- }
- return rc;
-}
-
-static inline u32 get_srstat(struct i2c_algo_iop3xx_data *iop3xx_adap)
-{
- unsigned long flags;
- u32 sr;
-
- spin_lock_irqsave(&iop3xx_adap->lock, flags);
- sr = iop3xx_adap->biu->SR_received;
- iop3xx_adap->biu->SR_received = 0;
- spin_unlock_irqrestore(&iop3xx_adap->lock, flags);
-
- return sr;
-}
-
-/*
- * sleep until interrupted, then recover and analyse the SR
- * saved by handler
- */
-typedef int (* compare_func)(unsigned test, unsigned mask);
-/* returns 1 on correct comparison */
-
-static int iop3xx_adap_wait_event(struct i2c_algo_iop3xx_data *iop3xx_adap,
- unsigned flags, unsigned* status,
- compare_func compare)
-{
- unsigned sr = 0;
- int interrupted;
- int done;
- int rc;
-
- do {
- interrupted = wait_event_interruptible_timeout (
- iop3xx_adap->waitq,
- (done = compare( sr = get_srstat(iop3xx_adap),flags )),
- iop3xx_adap->timeout
- );
- if ((rc = iop3xx_adap_error(sr)) < 0) {
- *status = sr;
- return rc;
- }else if (!interrupted) {
- *status = sr;
- return rc = -ETIMEDOUT;
- }
- } while(!done);
-
- *status = sr;
-
- return rc = 0;
-}
-
-/*
- * Concrete compare_funcs
- */
-static int all_bits_clear(unsigned test, unsigned mask)
-{
- return (test & mask) == 0;
-}
-static int any_bits_set(unsigned test, unsigned mask)
-{
- return (test & mask) != 0;
-}
-
-static int iop3xx_adap_wait_tx_done(struct i2c_algo_iop3xx_data *iop3xx_adap, int *status)
-{
- return iop3xx_adap_wait_event(
- iop3xx_adap,
- IOP321_ISR_TXEMPTY|IOP321_ISR_ALD|IOP321_ISR_BERRD,
- status, any_bits_set);
-}
-
-static int iop3xx_adap_wait_rx_done(struct i2c_algo_iop3xx_data *iop3xx_adap, int *status)
-{
- return iop3xx_adap_wait_event(
- iop3xx_adap,
- IOP321_ISR_RXFULL|IOP321_ISR_ALD|IOP321_ISR_BERRD,
- status, any_bits_set);
-}
-
-static int iop3xx_adap_wait_idle(struct i2c_algo_iop3xx_data *iop3xx_adap, int *status)
-{
- return iop3xx_adap_wait_event(
- iop3xx_adap, IOP321_ISR_UNITBUSY, status, all_bits_clear);
-}
-
-/*
- * Description: This performs the IOP3xx initialization sequence
- * Valid for IOP321. Maybe valid for IOP310?.
- */
-static int iop3xx_adap_init (struct i2c_algo_iop3xx_data *iop3xx_adap)
-{
- *IOP321_GPOD &= ~(iop3xx_adap->channel==0 ?
- IOP321_GPOD_I2C0:
- IOP321_GPOD_I2C1);
-
- iop3xx_adap_reset(iop3xx_adap);
- iop3xx_adap_set_slave_addr(iop3xx_adap);
- iop3xx_adap_enable(iop3xx_adap);
-
- return 0;
-}
-
-static int iop3xx_adap_send_target_slave_addr(struct i2c_algo_iop3xx_data *iop3xx_adap,
- struct i2c_msg* msg)
-{
- unsigned cr = *iop3xx_adap->biu->CR;
- int status;
- int rc;
-
- *iop3xx_adap->biu->DBR = iic_cook_addr(msg);
-
- cr &= ~(IOP321_ICR_MSTOP | IOP321_ICR_NACK);
- cr |= IOP321_ICR_MSTART | IOP321_ICR_TBYTE;
-
- *iop3xx_adap->biu->CR = cr;
- rc = iop3xx_adap_wait_tx_done(iop3xx_adap, &status);
- /* this assert fires every time, contrary to IOP manual
- PASSERT((status&IOP321_ISR_UNITBUSY)!=0);
- */
- PASSERT((status&IOP321_ISR_RXREAD)==0);
-
- return rc;
-}
-
-static int iop3xx_adap_write_byte(struct i2c_algo_iop3xx_data *iop3xx_adap, char byte, int stop)
-{
- unsigned cr = *iop3xx_adap->biu->CR;
- int status;
- int rc;
-
- *iop3xx_adap->biu->DBR = byte;
- cr &= ~IOP321_ICR_MSTART;
- if (stop) {
- cr |= IOP321_ICR_MSTOP;
- } else {
- cr &= ~IOP321_ICR_MSTOP;
- }
- *iop3xx_adap->biu->CR = cr |= IOP321_ICR_TBYTE;
- rc = iop3xx_adap_wait_tx_done(iop3xx_adap, &status);
-
- return rc;
-}
-
-static int iop3xx_adap_read_byte(struct i2c_algo_iop3xx_data *iop3xx_adap,
- char* byte, int stop)
-{
- unsigned cr = *iop3xx_adap->biu->CR;
- int status;
- int rc;
-
- cr &= ~IOP321_ICR_MSTART;
-
- if (stop) {
- cr |= IOP321_ICR_MSTOP|IOP321_ICR_NACK;
- } else {
- cr &= ~(IOP321_ICR_MSTOP|IOP321_ICR_NACK);
- }
- *iop3xx_adap->biu->CR = cr |= IOP321_ICR_TBYTE;
-
- rc = iop3xx_adap_wait_rx_done(iop3xx_adap, &status);
-
- *byte = *iop3xx_adap->biu->DBR;
-
- return rc;
-}
-
-static int iop3xx_i2c_writebytes(struct i2c_adapter *i2c_adap,
- const char *buf, int count)
-{
- struct i2c_algo_iop3xx_data *iop3xx_adap = i2c_adap->algo_data;
- int ii;
- int rc = 0;
-
- for (ii = 0; rc == 0 && ii != count; ++ii) {
- rc = iop3xx_adap_write_byte(iop3xx_adap, buf[ii], ii==count-1);
- }
- return rc;
-}
-
-static int iop3xx_i2c_readbytes(struct i2c_adapter *i2c_adap,
- char *buf, int count)
-{
- struct i2c_algo_iop3xx_data *iop3xx_adap = i2c_adap->algo_data;
- int ii;
- int rc = 0;
-
- for (ii = 0; rc == 0 && ii != count; ++ii) {
- rc = iop3xx_adap_read_byte(iop3xx_adap, &buf[ii], ii==count-1);
- }
- return rc;
-}
-
-/*
- * Description: This function implements combined transactions. Combined
- * transactions consist of combinations of reading and writing blocks of data.
- * FROM THE SAME ADDRESS
- * Each transfer (i.e. a read or a write) is separated by a repeated start
- * condition.
- */
-static int iop3xx_handle_msg(struct i2c_adapter *i2c_adap, struct i2c_msg* pmsg)
-{
- struct i2c_algo_iop3xx_data *iop3xx_adap = i2c_adap->algo_data;
- int rc;
-
- rc = iop3xx_adap_send_target_slave_addr(iop3xx_adap, pmsg);
- if (rc < 0) {
- return rc;
- }
-
- if ((pmsg->flags&I2C_M_RD)) {
- return iop3xx_i2c_readbytes(i2c_adap, pmsg->buf, pmsg->len);
- } else {
- return iop3xx_i2c_writebytes(i2c_adap, pmsg->buf, pmsg->len);
- }
-}
-
-/*
- * master_xfer() - main read/write entry
- */
-static int iop3xx_master_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num)
-{
- struct i2c_algo_iop3xx_data *iop3xx_adap = i2c_adap->algo_data;
- int im = 0;
- int ret = 0;
- int status;
-
- iop3xx_adap_wait_idle(iop3xx_adap, &status);
- iop3xx_adap_reset(iop3xx_adap);
- iop3xx_adap_enable(iop3xx_adap);
-
- for (im = 0; ret == 0 && im != num; ++im) {
- ret = iop3xx_handle_msg(i2c_adap, &msgs[im]);
- }
-
- iop3xx_adap_transaction_cleanup(iop3xx_adap);
-
- return ret;
-}
-
-static int algo_control(struct i2c_adapter *adapter, unsigned int cmd,
- unsigned long arg)
-{
- return 0;
-}
-
-static u32 iic_func(struct i2c_adapter *adap)
-{
- return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
-}
-
-
-/* -----exported algorithm data: ------------------------------------- */
-
-static struct i2c_algorithm iic_algo = {
- .name = "IOP3xx I2C algorithm",
- .id = I2C_ALGO_OCP_IOP3XX,
- .master_xfer = iop3xx_master_xfer,
- .algo_control = algo_control,
- .functionality = iic_func,
-};
-
-/*
- * registering functions to load algorithms at runtime
- */
-static int i2c_iop3xx_add_bus(struct i2c_adapter *iic_adap)
-{
- struct i2c_algo_iop3xx_data *iop3xx_adap = iic_adap->algo_data;
-
- if (!request_region( REGION_START(iop3xx_adap),
- REGION_LENGTH(iop3xx_adap),
- iic_adap->name)) {
- return -ENODEV;
- }
-
- init_waitqueue_head(&iop3xx_adap->waitq);
- spin_lock_init(&iop3xx_adap->lock);
-
- if (request_irq(
- iop3xx_adap->biu->irq,
- iop3xx_i2c_handler,
- /* SA_SAMPLE_RANDOM */ 0,
- iic_adap->name,
- iop3xx_adap)) {
- return -ENODEV;
- }
-
- /* register new iic_adapter to i2c module... */
- iic_adap->id |= iic_algo.id;
- iic_adap->algo = &iic_algo;
-
- iic_adap->timeout = 100; /* default values, should */
- iic_adap->retries = 3; /* be replaced by defines */
-
- iop3xx_adap_init(iic_adap->algo_data);
- i2c_add_adapter(iic_adap);
- return 0;
-}
-
-static int i2c_iop3xx_del_bus(struct i2c_adapter *iic_adap)
-{
- struct i2c_algo_iop3xx_data *iop3xx_adap = iic_adap->algo_data;
-
- iop3xx_adap_final_cleanup(iop3xx_adap);
- free_irq(iop3xx_adap->biu->irq, iop3xx_adap);
-
- release_region(REGION_START(iop3xx_adap), REGION_LENGTH(iop3xx_adap));
-
- return i2c_del_adapter(iic_adap);
-}
-
-#ifdef CONFIG_ARCH_IOP321
-
-static struct iop3xx_biu biu0 = {
- .CR = IOP321_ICR0,
- .SR = IOP321_ISR0,
- .SAR = IOP321_ISAR0,
- .DBR = IOP321_IDBR0,
- .BMR = IOP321_IBMR0,
- .irq = IRQ_IOP321_I2C_0,
-};
-
-static struct iop3xx_biu biu1 = {
- .CR = IOP321_ICR1,
- .SR = IOP321_ISR1,
- .SAR = IOP321_ISAR1,
- .DBR = IOP321_IDBR1,
- .BMR = IOP321_IBMR1,
- .irq = IRQ_IOP321_I2C_1,
-};
-
-#define ADAPTER_NAME_ROOT "IOP321 i2c biu adapter "
-#else
-#error Please define the BIU struct iop3xx_biu for your processor arch
-#endif
-
-static struct i2c_algo_iop3xx_data algo_iop3xx_data0 = {
- .channel = 0,
- .biu = &biu0,
- .timeout = 1*HZ,
-};
-static struct i2c_algo_iop3xx_data algo_iop3xx_data1 = {
- .channel = 1,
- .biu = &biu1,
- .timeout = 1*HZ,
-};
-
-static struct i2c_adapter iop3xx_ops0 = {
- .owner = THIS_MODULE,
- .name = ADAPTER_NAME_ROOT "0",
- .id = I2C_HW_IOP321,
- .algo_data = &algo_iop3xx_data0,
-};
-static struct i2c_adapter iop3xx_ops1 = {
- .owner = THIS_MODULE,
- .name = ADAPTER_NAME_ROOT "1",
- .id = I2C_HW_IOP321,
- .algo_data = &algo_iop3xx_data1,
-};
-
-static int __init i2c_iop3xx_init (void)
-{
- return i2c_iop3xx_add_bus(&iop3xx_ops0) ||
- i2c_iop3xx_add_bus(&iop3xx_ops1);
-}
-
-static void __exit i2c_iop3xx_exit (void)
-{
- i2c_iop3xx_del_bus(&iop3xx_ops0);
- i2c_iop3xx_del_bus(&iop3xx_ops1);
-}
-
-module_init (i2c_iop3xx_init);
-module_exit (i2c_iop3xx_exit);
-
-MODULE_AUTHOR("D-TACQ Solutions Ltd <www.d-tacq.com>");
-MODULE_DESCRIPTION("IOP3xx iic algorithm and driver");
-MODULE_LICENSE("GPL");
-
-MODULE_PARM(i2c_debug,"i");
-
-MODULE_PARM_DESC(i2c_debug, "debug level - 0 off; 1 normal; 2,3 more verbose; 9 iic-protocol");
-
+++ /dev/null
-/* ------------------------------------------------------------------------- */
-/* i2c-iop3xx.h algorithm driver definitions private to i2c-iop3xx.c */
-/* ------------------------------------------------------------------------- */
-/* Copyright (C) 2003 Peter Milne, D-TACQ Solutions Ltd
- * <Peter dot Milne at D hyphen TACQ dot com>
-
- 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, version 2.
-
- 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_IOP3XX_H
-#define I2C_IOP3XX_H 1
-
-/*
- * iop321 hardware bit definitions
- */
-#define IOP321_ICR_FAST_MODE 0x8000 /* 1=400kBps, 0=100kBps */
-#define IOP321_ICR_UNIT_RESET 0x4000 /* 1=RESET */
-#define IOP321_ICR_SADIE 0x2000 /* 1=Slave Detect Interrupt Enable */
-#define IOP321_ICR_ALDIE 0x1000 /* 1=Arb Loss Detect Interrupt Enable */
-#define IOP321_ICR_SSDIE 0x0800 /* 1=Slave STOP Detect Interrupt Enable */
-#define IOP321_ICR_BERRIE 0x0400 /* 1=Bus Error Interrupt Enable */
-#define IOP321_ICR_RXFULLIE 0x0200 /* 1=Receive Full Interrupt Enable */
-#define IOP321_ICR_TXEMPTYIE 0x0100 /* 1=Transmit Empty Interrupt Enable */
-#define IOP321_ICR_GCD 0x0080 /* 1=General Call Disable */
-/*
- * IOP321_ICR_GCD: 1 disables response as slave. "This bit must be set
- * when sending a master mode general call message from the I2C unit"
- */
-#define IOP321_ICR_UE 0x0040 /* 1=Unit Enable */
-/*
- * "NOTE: To avoid I2C bus integrity problems,
- * the user needs to ensure that the GPIO Output Data Register -
- * GPOD bits associated with an I2C port are cleared prior to setting
- * the enable bit for that I2C serial port.
- * The user prepares to enable I2C port 0 and
- * I2C port 1 by clearing GPOD bits 7:6 and GPOD bits 5:4, respectively.
- */
-#define IOP321_ICR_SCLEN 0x0020 /* 1=SCL enable for master mode */
-#define IOP321_ICR_MABORT 0x0010 /* 1=Send a STOP with no data
- * NB TBYTE must be clear */
-#define IOP321_ICR_TBYTE 0x0008 /* 1=Send/Receive a byte. i2c clears */
-#define IOP321_ICR_NACK 0x0004 /* 1=reply with NACK */
-#define IOP321_ICR_MSTOP 0x0002 /* 1=send a STOP after next data byte */
-#define IOP321_ICR_MSTART 0x0001 /* 1=initiate a START */
-
-
-#define IOP321_ISR_BERRD 0x0400 /* 1=BUS ERROR Detected */
-#define IOP321_ISR_SAD 0x0200 /* 1=Slave ADdress Detected */
-#define IOP321_ISR_GCAD 0x0100 /* 1=General Call Address Detected */
-#define IOP321_ISR_RXFULL 0x0080 /* 1=Receive Full */
-#define IOP321_ISR_TXEMPTY 0x0040 /* 1=Transmit Empty */
-#define IOP321_ISR_ALD 0x0020 /* 1=Arbitration Loss Detected */
-#define IOP321_ISR_SSD 0x0010 /* 1=Slave STOP Detected */
-#define IOP321_ISR_BBUSY 0x0008 /* 1=Bus BUSY */
-#define IOP321_ISR_UNITBUSY 0x0004 /* 1=Unit Busy */
-#define IOP321_ISR_NACK 0x0002 /* 1=Unit Rx or Tx a NACK */
-#define IOP321_ISR_RXREAD 0x0001 /* 1=READ 0=WRITE (R/W bit of slave addr */
-
-#define IOP321_ISR_CLEARBITS 0x07f0
-
-#define IOP321_ISAR_SAMASK 0x007f
-
-#define IOP321_IDBR_MASK 0x00ff
-
-#define IOP321_IBMR_SCL 0x0002
-#define IOP321_IBMR_SDA 0x0001
-
-#define IOP321_GPOD_I2C0 0x00c0 /* clear these bits to enable ch0 */
-#define IOP321_GPOD_I2C1 0x0030 /* clear these bits to enable ch1 */
-
-#define MYSAR 0x02 /* SWAG a suitable slave address */
-
-#define I2C_ERR 321
-#define I2C_ERR_BERR (I2C_ERR+0)
-#define I2C_ERR_ALD (I2C_ERR+1)
-
-
-struct iop3xx_biu { /* Bus Interface Unit - the hardware */
-/* physical hardware defs - regs*/
- u32 *CR;
- u32 *SR;
- u32 *SAR;
- u32 *DBR;
- u32 *BMR;
-/* irq bit vector */
- u32 irq;
-/* stored flags */
- u32 SR_enabled, SR_received;
-};
-
-struct i2c_algo_iop3xx_data {
- int channel;
-
- wait_queue_head_t waitq;
- spinlock_t lock;
- int timeout;
- struct iop3xx_biu* biu;
-};
-
-#define REGION_START(adap) ((u32)((adap)->biu->CR))
-#define REGION_END(adap) ((u32)((adap)->biu->BMR+1))
-#define REGION_LENGTH(adap) (REGION_END(adap)-REGION_START(adap))
-
-#define IRQ_STATUS_MASK(adap) (1<<adap->biu->irq)
-
-#endif /* I2C_IOP3XX_H */
+++ /dev/null
-/*
- i2c Support for Apple Keywest I2C Bus Controller
-
- Copyright (c) 2001 Benjamin Herrenschmidt <benh@kernel.crashing.org>
-
- Original work by
-
- Copyright (c) 2000 Philip Edelbrock <phil@stimpy.netroedge.com>
-
- 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.
-
- Changes:
-
- 2001/12/13 BenH New implementation
- 2001/12/15 BenH Add support for "byte" and "quick"
- transfers. Add i2c_xfer routine.
-
- My understanding of the various modes supported by keywest are:
-
- - Dumb mode : not implemented, probably direct tweaking of lines
- - Standard mode : simple i2c transaction of type
- S Addr R/W A Data A Data ... T
- - Standard sub mode : combined 8 bit subaddr write with data read
- S Addr R/W A SubAddr A Data A Data ... T
- - Combined mode : Subaddress and Data sequences appended with no stop
- S Addr R/W A SubAddr S Addr R/W A Data A Data ... T
-
- Currently, this driver uses only Standard mode for i2c xfer, and
- smbus byte & quick transfers ; and uses StandardSub mode for
- other smbus transfers instead of combined as we need that for the
- sound driver to be happy
-*/
-
-#include <linux/module.h>
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/ioport.h>
-#include <linux/pci.h>
-#include <linux/types.h>
-#include <linux/delay.h>
-#include <linux/i2c.h>
-#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/timer.h>
-#include <linux/spinlock.h>
-#include <linux/completion.h>
-#include <linux/interrupt.h>
-
-#include <asm/io.h>
-#include <asm/prom.h>
-#include <asm/machdep.h>
-#include <asm/pmac_feature.h>
-
-#include "i2c-keywest.h"
-
-#define DBG(x...) do {\
- if (debug > 0) \
- printk(KERN_DEBUG "KW:" x); \
- } while(0)
-
-
-MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
-MODULE_DESCRIPTION("I2C driver for Apple's Keywest");
-MODULE_LICENSE("GPL");
-MODULE_PARM(probe, "i");
-MODULE_PARM(debug, "i");
-
-int probe = 0;
-int debug = 0;
-
-static void
-do_stop(struct keywest_iface* iface, int result)
-{
- write_reg(reg_control, read_reg(reg_control) | KW_I2C_CTL_STOP);
- iface->state = state_stop;
- iface->result = result;
-}
-
-/* Main state machine for standard & standard sub mode */
-static int
-handle_interrupt(struct keywest_iface *iface, u8 isr)
-{
- int ack;
- int rearm_timer = 1;
-
- DBG("handle_interrupt(), got: %x, status: %x, state: %d\n",
- isr, read_reg(reg_status), iface->state);
- if (isr == 0 && iface->state != state_stop) {
- do_stop(iface, -1);
- return rearm_timer;
- }
- if (isr & KW_I2C_IRQ_STOP && iface->state != state_stop) {
- iface->result = -1;
- iface->state = state_stop;
- }
- switch(iface->state) {
- case state_addr:
- if (!(isr & KW_I2C_IRQ_ADDR)) {
- do_stop(iface, -1);
- break;
- }
- ack = read_reg(reg_status);
- DBG("ack on set address: %x\n", ack);
- if ((ack & KW_I2C_STAT_LAST_AAK) == 0) {
- do_stop(iface, -1);
- break;
- }
- /* Handle rw "quick" mode */
- if (iface->datalen == 0)
- do_stop(iface, 0);
- else if (iface->read_write == I2C_SMBUS_READ) {
- iface->state = state_read;
- if (iface->datalen > 1)
- write_reg(reg_control, read_reg(reg_control)
- | KW_I2C_CTL_AAK);
- } else {
- iface->state = state_write;
- DBG("write byte: %x\n", *(iface->data));
- write_reg(reg_data, *(iface->data++));
- iface->datalen--;
- }
-
- break;
- case state_read:
- if (!(isr & KW_I2C_IRQ_DATA)) {
- do_stop(iface, -1);
- break;
- }
- *(iface->data++) = read_reg(reg_data);
- DBG("read byte: %x\n", *(iface->data-1));
- iface->datalen--;
- if (iface->datalen == 0)
- iface->state = state_stop;
- else
- write_reg(reg_control, 0);
- break;
- case state_write:
- if (!(isr & KW_I2C_IRQ_DATA)) {
- do_stop(iface, -1);
- break;
- }
- /* Check ack status */
- ack = read_reg(reg_status);
- DBG("ack on data write: %x\n", ack);
- if ((ack & KW_I2C_STAT_LAST_AAK) == 0) {
- do_stop(iface, -1);
- break;
- }
- if (iface->datalen) {
- DBG("write byte: %x\n", *(iface->data));
- write_reg(reg_data, *(iface->data++));
- iface->datalen--;
- } else
- do_stop(iface, 0);
- break;
-
- case state_stop:
- if (!(isr & KW_I2C_IRQ_STOP) && (++iface->stopretry) < 10)
- do_stop(iface, -1);
- else {
- rearm_timer = 0;
- iface->state = state_idle;
- write_reg(reg_control, 0x00);
- write_reg(reg_ier, 0x00);
- complete(&iface->complete);
- }
- break;
- }
-
- write_reg(reg_isr, isr);
-
- return rearm_timer;
-}
-
-/* Interrupt handler */
-static irqreturn_t
-keywest_irq(int irq, void *dev_id, struct pt_regs *regs)
-{
- struct keywest_iface *iface = (struct keywest_iface *)dev_id;
-
- spin_lock(&iface->lock);
- del_timer(&iface->timeout_timer);
- if (handle_interrupt(iface, read_reg(reg_isr)))
- mod_timer(&iface->timeout_timer, jiffies + POLL_TIMEOUT);
- spin_unlock(&iface->lock);
- return IRQ_HANDLED;
-}
-
-static void
-keywest_timeout(unsigned long data)
-{
- struct keywest_iface *iface = (struct keywest_iface *)data;
-
- DBG("timeout !\n");
- spin_lock_irq(&iface->lock);
- if (handle_interrupt(iface, read_reg(reg_isr)))
- mod_timer(&iface->timeout_timer, jiffies + POLL_TIMEOUT);
- spin_unlock(&iface->lock);
-}
-
-/*
- * SMBUS-type transfer entrypoint
- */
-static s32
-keywest_smbus_xfer( struct i2c_adapter* adap,
- u16 addr,
- unsigned short flags,
- char read_write,
- u8 command,
- int size,
- union i2c_smbus_data* data)
-{
- struct keywest_chan* chan = i2c_get_adapdata(adap);
- struct keywest_iface* iface = chan->iface;
- int len;
- u8* buffer;
- u16 cur_word;
- int rc = 0;
-
- if (iface->state == state_dead)
- return -1;
-
- /* Prepare datas & select mode */
- iface->cur_mode &= ~KW_I2C_MODE_MODE_MASK;
- switch (size) {
- case I2C_SMBUS_QUICK:
- len = 0;
- buffer = NULL;
- iface->cur_mode |= KW_I2C_MODE_STANDARD;
- break;
- case I2C_SMBUS_BYTE:
- len = 1;
- buffer = &data->byte;
- iface->cur_mode |= KW_I2C_MODE_STANDARD;
- break;
- case I2C_SMBUS_BYTE_DATA:
- len = 1;
- buffer = &data->byte;
- iface->cur_mode |= KW_I2C_MODE_STANDARDSUB;
- break;
- case I2C_SMBUS_WORD_DATA:
- len = 2;
- cur_word = cpu_to_le16(data->word);
- buffer = (u8 *)&cur_word;
- iface->cur_mode |= KW_I2C_MODE_STANDARDSUB;
- break;
- case I2C_SMBUS_BLOCK_DATA:
- len = data->block[0];
- buffer = &data->block[1];
- iface->cur_mode |= KW_I2C_MODE_STANDARDSUB;
- break;
- default:
- return -1;
- }
-
- /* Original driver had this limitation */
- if (len > 32)
- len = 32;
-
- down(&iface->sem);
-
- DBG("chan: %d, addr: 0x%x, transfer len: %d, read: %d\n",
- chan->chan_no, addr, len, read_write == I2C_SMBUS_READ);
-
- iface->data = buffer;
- iface->datalen = len;
- iface->state = state_addr;
- iface->result = 0;
- iface->stopretry = 0;
- iface->read_write = read_write;
-
- /* Setup channel & clear pending irqs */
- write_reg(reg_mode, iface->cur_mode | (chan->chan_no << 4));
- write_reg(reg_isr, read_reg(reg_isr));
- write_reg(reg_status, 0);
-
- /* Set up address and r/w bit */
- write_reg(reg_addr,
- (addr << 1) | ((read_write == I2C_SMBUS_READ) ? 0x01 : 0x00));
-
- /* Set up the sub address */
- if ((iface->cur_mode & KW_I2C_MODE_MODE_MASK) == KW_I2C_MODE_STANDARDSUB
- || (iface->cur_mode & KW_I2C_MODE_MODE_MASK) == KW_I2C_MODE_COMBINED)
- write_reg(reg_subaddr, command);
-
- /* Arm timeout */
- mod_timer(&iface->timeout_timer, jiffies + POLL_TIMEOUT);
-
- /* Start sending address & enable interrupt*/
- write_reg(reg_control, read_reg(reg_control) | KW_I2C_CTL_XADDR);
- write_reg(reg_ier, KW_I2C_IRQ_MASK);
-
- /* Wait interrupt operations completion */
- wait_for_completion(&iface->complete);
-
- rc = iface->result;
- DBG("transfer done, result: %d\n", rc);
-
- if (rc == 0 && size == I2C_SMBUS_WORD_DATA && read_write == I2C_SMBUS_READ)
- data->word = le16_to_cpu(cur_word);
-
- /* Release sem */
- up(&iface->sem);
-
- return rc;
-}
-
-/*
- * Generic i2c master transfer entrypoint
- */
-static int
-keywest_xfer( struct i2c_adapter *adap,
- struct i2c_msg msgs[],
- int num)
-{
- struct keywest_chan* chan = i2c_get_adapdata(adap);
- struct keywest_iface* iface = chan->iface;
- struct i2c_msg *pmsg;
- int i, completed;
- int rc = 0;
-
- down(&iface->sem);
-
- /* Set adapter to standard mode */
- iface->cur_mode &= ~KW_I2C_MODE_MODE_MASK;
- iface->cur_mode |= KW_I2C_MODE_STANDARD;
-
- completed = 0;
- for (i = 0; rc >= 0 && i < num;) {
- u8 addr;
-
- pmsg = &msgs[i++];
- addr = pmsg->addr;
- if (pmsg->flags & I2C_M_TEN) {
- printk(KERN_ERR "i2c-keywest: 10 bits addr not supported !\n");
- rc = -EINVAL;
- break;
- }
- DBG("xfer: chan: %d, doing %s %d bytes to 0x%02x - %d of %d messages\n",
- chan->chan_no,
- pmsg->flags & I2C_M_RD ? "read" : "write",
- pmsg->len, addr, i, num);
-
- /* Setup channel & clear pending irqs */
- write_reg(reg_mode, iface->cur_mode | (chan->chan_no << 4));
- write_reg(reg_isr, read_reg(reg_isr));
- write_reg(reg_status, 0);
-
- iface->data = pmsg->buf;
- iface->datalen = pmsg->len;
- iface->state = state_addr;
- iface->result = 0;
- iface->stopretry = 0;
- if (pmsg->flags & I2C_M_RD)
- iface->read_write = I2C_SMBUS_READ;
- else
- iface->read_write = I2C_SMBUS_WRITE;
-
- /* Set up address and r/w bit */
- if (pmsg->flags & I2C_M_REV_DIR_ADDR)
- addr ^= 1;
- write_reg(reg_addr,
- (addr << 1) |
- ((iface->read_write == I2C_SMBUS_READ) ? 0x01 : 0x00));
-
- /* Arm timeout */
- mod_timer(&iface->timeout_timer, jiffies + POLL_TIMEOUT);
-
- /* Start sending address & enable interrupt*/
- write_reg(reg_control, read_reg(reg_control) | KW_I2C_CTL_XADDR);
- write_reg(reg_ier, KW_I2C_IRQ_MASK);
-
- /* Wait interrupt operations completion */
- wait_for_completion(&iface->complete);
-
- rc = iface->result;
- if (rc == 0)
- completed++;
- DBG("transfer done, result: %d\n", rc);
- }
-
- /* Release sem */
- up(&iface->sem);
-
- return completed;
-}
-
-static u32
-keywest_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;
-}
-
-/* For now, we only handle combined mode (smbus) */
-static struct i2c_algorithm keywest_algorithm = {
- .name = "Keywest i2c",
- .id = I2C_ALGO_SMBUS,
- .smbus_xfer = keywest_smbus_xfer,
- .master_xfer = keywest_xfer,
- .functionality = keywest_func,
-};
-
-
-static int
-create_iface(struct device_node *np, struct device *dev)
-{
- unsigned long steps, *psteps, *prate;
- unsigned bsteps, tsize, i, nchan, addroffset;
- struct keywest_iface* iface;
- int rc;
-
- psteps = (unsigned long *)get_property(np, "AAPL,address-step", NULL);
- steps = psteps ? (*psteps) : 0x10;
-
- /* Hrm... maybe we can be smarter here */
- for (bsteps = 0; (steps & 0x01) == 0; bsteps++)
- steps >>= 1;
-
- if (!strcmp(np->parent->name, "uni-n")) {
- nchan = 2;
- addroffset = 3;
- } else {
- addroffset = 0;
- nchan = 1;
- }
-
- tsize = sizeof(struct keywest_iface) +
- (sizeof(struct keywest_chan) + 4) * nchan;
- iface = (struct keywest_iface *) kmalloc(tsize, GFP_KERNEL);
- if (iface == NULL) {
- printk(KERN_ERR "i2c-keywest: can't allocate inteface !\n");
- return -ENOMEM;
- }
- memset(iface, 0, tsize);
- init_MUTEX(&iface->sem);
- spin_lock_init(&iface->lock);
- init_completion(&iface->complete);
- iface->bsteps = bsteps;
- iface->chan_count = nchan;
- iface->state = state_idle;
- iface->irq = np->intrs[0].line;
- iface->channels = (struct keywest_chan *)
- (((unsigned long)(iface + 1) + 3UL) & ~3UL);
- iface->base = (unsigned long)ioremap(np->addrs[0].address + addroffset,
- np->addrs[0].size);
- if (iface->base == 0) {
- printk(KERN_ERR "i2c-keywest: can't map inteface !\n");
- kfree(iface);
- return -ENOMEM;
- }
-
- init_timer(&iface->timeout_timer);
- iface->timeout_timer.function = keywest_timeout;
- iface->timeout_timer.data = (unsigned long)iface;
-
- /* Select interface rate */
- iface->cur_mode = KW_I2C_MODE_100KHZ;
- prate = (unsigned long *)get_property(np, "AAPL,i2c-rate", NULL);
- if (prate) switch(*prate) {
- case 100:
- iface->cur_mode = KW_I2C_MODE_100KHZ;
- break;
- case 50:
- iface->cur_mode = KW_I2C_MODE_50KHZ;
- break;
- case 25:
- iface->cur_mode = KW_I2C_MODE_25KHZ;
- break;
- default:
- printk(KERN_WARNING "i2c-keywest: unknown rate %ldKhz, using 100KHz\n",
- *prate);
- }
-
- /* Select standard sub mode */
- iface->cur_mode |= KW_I2C_MODE_STANDARDSUB;
-
- /* Write mode */
- write_reg(reg_mode, iface->cur_mode);
-
- /* Switch interrupts off & clear them*/
- write_reg(reg_ier, 0x00);
- write_reg(reg_isr, KW_I2C_IRQ_MASK);
-
- /* Request chip interrupt */
- rc = request_irq(iface->irq, keywest_irq, 0, "keywest i2c", iface);
- if (rc) {
- printk(KERN_ERR "i2c-keywest: can't get IRQ %d !\n", iface->irq);
- iounmap((void *)iface->base);
- kfree(iface);
- return -ENODEV;
- }
-
- dev_set_drvdata(dev, iface);
-
- for (i=0; i<nchan; i++) {
- struct keywest_chan* chan = &iface->channels[i];
- u8 addr;
-
- sprintf(chan->adapter.name, "%s %d", np->parent->name, i);
- chan->iface = iface;
- chan->chan_no = i;
- chan->adapter.id = I2C_ALGO_SMBUS;
- chan->adapter.algo = &keywest_algorithm;
- chan->adapter.algo_data = NULL;
- chan->adapter.client_register = NULL;
- chan->adapter.client_unregister = NULL;
- i2c_set_adapdata(&chan->adapter, chan);
- chan->adapter.dev.parent = dev;
-
- rc = i2c_add_adapter(&chan->adapter);
- if (rc) {
- printk("i2c-keywest.c: Adapter %s registration failed\n",
- chan->adapter.name);
- i2c_set_adapdata(&chan->adapter, NULL);
- }
- if (probe) {
- printk("Probe: ");
- for (addr = 0x00; addr <= 0x7f; addr++) {
- if (i2c_smbus_xfer(&chan->adapter,addr,
- 0,0,0,I2C_SMBUS_QUICK,NULL) >= 0)
- printk("%02x ", addr);
- }
- printk("\n");
- }
- }
-
- printk(KERN_INFO "Found KeyWest i2c on \"%s\", %d channel%s, stepping: %d bits\n",
- np->parent->name, nchan, nchan > 1 ? "s" : "", bsteps);
-
- return 0;
-}
-
-static int
-dispose_iface(struct device *dev)
-{
- struct keywest_iface *iface = dev_get_drvdata(dev);
- int i, rc;
-
- /* Make sure we stop all activity */
- down(&iface->sem);
-
- spin_lock_irq(&iface->lock);
- while (iface->state != state_idle) {
- spin_unlock_irq(&iface->lock);
- set_task_state(current,TASK_UNINTERRUPTIBLE);
- schedule_timeout(HZ/10);
- spin_lock_irq(&iface->lock);
- }
- iface->state = state_dead;
- spin_unlock_irq(&iface->lock);
- free_irq(iface->irq, iface);
- up(&iface->sem);
-
- /* Release all channels */
- for (i=0; i<iface->chan_count; i++) {
- struct keywest_chan* chan = &iface->channels[i];
- if (i2c_get_adapdata(&chan->adapter) == NULL)
- continue;
- rc = i2c_del_adapter(&chan->adapter);
- i2c_set_adapdata(&chan->adapter, NULL);
- /* We aren't that prepared to deal with this... */
- if (rc)
- printk("i2c-keywest.c: i2c_del_adapter failed, that's bad !\n");
- }
- iounmap((void *)iface->base);
- dev_set_drvdata(dev, NULL);
- kfree(iface);
-
- return 0;
-}
-
-static int
-create_iface_macio(struct macio_dev* dev, const struct of_match *match)
-{
- return create_iface(dev->ofdev.node, &dev->ofdev.dev);
-}
-
-static int
-dispose_iface_macio(struct macio_dev* dev)
-{
- return dispose_iface(&dev->ofdev.dev);
-}
-
-static int
-create_iface_of_platform(struct of_device* dev, const struct of_match *match)
-{
- return create_iface(dev->node, &dev->dev);
-}
-
-static int
-dispose_iface_of_platform(struct of_device* dev)
-{
- return dispose_iface(&dev->dev);
-}
-
-static struct of_match i2c_keywest_match[] =
-{
- {
- .name = OF_ANY_MATCH,
- .type = "i2c",
- .compatible = "keywest"
- },
- {},
-};
-
-static struct macio_driver i2c_keywest_macio_driver =
-{
- .name = "i2c-keywest",
- .match_table = i2c_keywest_match,
- .probe = create_iface_macio,
- .remove = dispose_iface_macio
-};
-
-static struct of_platform_driver i2c_keywest_of_platform_driver =
-{
- .name = "i2c-keywest",
- .match_table = i2c_keywest_match,
- .probe = create_iface_of_platform,
- .remove = dispose_iface_of_platform
-};
-
-static int __init
-i2c_keywest_init(void)
-{
- macio_register_driver(&i2c_keywest_macio_driver);
- of_register_driver(&i2c_keywest_of_platform_driver);
-
- return 0;
-}
-
-static void __exit
-i2c_keywest_cleanup(void)
-{
- macio_unregister_driver(&i2c_keywest_macio_driver);
- of_unregister_driver(&i2c_keywest_of_platform_driver);
-}
-
-module_init(i2c_keywest_init);
-module_exit(i2c_keywest_cleanup);
+++ /dev/null
-#ifndef __I2C_KEYWEST_H__
-#define __I2C_KEYWEST_H__
-
-/* The Tumbler audio equalizer can be really slow sometimes */
-#define POLL_TIMEOUT (2*HZ)
-
-/* Register indices */
-typedef enum {
- reg_mode = 0,
- reg_control,
- reg_status,
- reg_isr,
- reg_ier,
- reg_addr,
- reg_subaddr,
- reg_data
-} reg_t;
-
-
-/* Mode register */
-#define KW_I2C_MODE_100KHZ 0x00
-#define KW_I2C_MODE_50KHZ 0x01
-#define KW_I2C_MODE_25KHZ 0x02
-#define KW_I2C_MODE_DUMB 0x00
-#define KW_I2C_MODE_STANDARD 0x04
-#define KW_I2C_MODE_STANDARDSUB 0x08
-#define KW_I2C_MODE_COMBINED 0x0C
-#define KW_I2C_MODE_MODE_MASK 0x0C
-#define KW_I2C_MODE_CHAN_MASK 0xF0
-
-/* Control register */
-#define KW_I2C_CTL_AAK 0x01
-#define KW_I2C_CTL_XADDR 0x02
-#define KW_I2C_CTL_STOP 0x04
-#define KW_I2C_CTL_START 0x08
-
-/* Status register */
-#define KW_I2C_STAT_BUSY 0x01
-#define KW_I2C_STAT_LAST_AAK 0x02
-#define KW_I2C_STAT_LAST_RW 0x04
-#define KW_I2C_STAT_SDA 0x08
-#define KW_I2C_STAT_SCL 0x10
-
-/* IER & ISR registers */
-#define KW_I2C_IRQ_DATA 0x01
-#define KW_I2C_IRQ_ADDR 0x02
-#define KW_I2C_IRQ_STOP 0x04
-#define KW_I2C_IRQ_START 0x08
-#define KW_I2C_IRQ_MASK 0x0F
-
-/* Physical interface */
-struct keywest_iface
-{
- unsigned long base;
- unsigned bsteps;
- int irq;
- struct semaphore sem;
- spinlock_t lock;
- struct keywest_chan* channels;
- unsigned chan_count;
- u8 cur_mode;
- char read_write;
- u8* data;
- unsigned datalen;
- int state;
- int result;
- int stopretry;
- struct timer_list timeout_timer;
- struct completion complete;
-};
-
-enum {
- state_idle,
- state_addr,
- state_read,
- state_write,
- state_stop,
- state_dead
-};
-
-/* Channel on an interface */
-struct keywest_chan
-{
- struct i2c_adapter adapter;
- struct keywest_iface* iface;
- unsigned chan_no;
-};
-
-/* Register access */
-
-static inline u8 __read_reg(struct keywest_iface *iface, reg_t reg)
-{
- return in_8(((volatile u8 *)iface->base)
- + (((unsigned)reg) << iface->bsteps));
-}
-
-static inline void __write_reg(struct keywest_iface *iface, reg_t reg, u8 val)
-{
- out_8(((volatile u8 *)iface->base)
- + (((unsigned)reg) << iface->bsteps), val);
- (void)__read_reg(iface, reg);
- udelay(10);
-}
-
-#define write_reg(reg, val) __write_reg(iface, reg, val)
-#define read_reg(reg) __read_reg(iface, reg)
-
-
-
-#endif /* __I2C_KEYWEST_H__ */
+++ /dev/null
-/*
- * Embedded Planet RPX Lite MPC8xx CPM I2C interface.
- * Copyright (c) 1999 Dan Malek (dmalek@jlc.net).
- *
- * moved into proper i2c interface;
- * Brad Parker (brad@heeltoe.com)
- *
- * RPX lite specific parts of the i2c interface
- * Update: There actually isn't anything RPXLite-specific about this module.
- * This should work for most any 8xx board. The console messages have been
- * changed to eliminate RPXLite references.
- */
-
-#include <linux/kernel.h>
-#include <linux/ioport.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/stddef.h>
-#include <linux/parport.h>
-#include <linux/i2c.h>
-#include <linux/i2c-algo-8xx.h>
-#include <asm/mpc8xx.h>
-#include <asm/commproc.h>
-
-
-static void
-rpx_iic_init(struct i2c_algo_8xx_data *data)
-{
- volatile cpm8xx_t *cp;
- volatile immap_t *immap;
-
- cp = cpmp; /* Get pointer to Communication Processor */
- immap = (immap_t *)IMAP_ADDR; /* and to internal registers */
-
- data->iip = (iic_t *)&cp->cp_dparam[PROFF_IIC];
-
- /* Check for and use a microcode relocation patch.
- */
- if ((data->reloc = data->iip->iic_rpbase))
- data->iip = (iic_t *)&cp->cp_dpmem[data->iip->iic_rpbase];
-
- data->i2c = (i2c8xx_t *)&(immap->im_i2c);
- data->cp = cp;
-
- /* Initialize Port B IIC pins.
- */
- cp->cp_pbpar |= 0x00000030;
- cp->cp_pbdir |= 0x00000030;
- cp->cp_pbodr |= 0x00000030;
-
- /* Allocate space for two transmit and two receive buffer
- * descriptors in the DP ram.
- */
- data->dp_addr = m8xx_cpm_dpalloc(sizeof(cbd_t) * 4);
-
- /* ptr to i2c area */
- data->i2c = (i2c8xx_t *)&(((immap_t *)IMAP_ADDR)->im_i2c);
-}
-
-static int rpx_install_isr(int irq, void (*func)(void *, void *), void *data)
-{
- /* install interrupt handler */
- cpm_install_handler(irq, (void (*)(void *, struct pt_regs *)) func, data);
-
- return 0;
-}
-
-static struct i2c_algo_8xx_data rpx_data = {
- .setisr = rpx_install_isr
-};
-
-static struct i2c_adapter rpx_ops = {
- .owner = THIS_MODULE,
- .name = "m8xx",
- .id = I2C_HW_MPC8XX_EPON,
- .algo_data = &rpx_data,
-};
-
-int __init i2c_rpx_init(void)
-{
- printk("i2c-rpx.o: i2c MPC8xx module version %s (%s)\n", I2C_VERSION, I2C_DATE);
-
- /* reset hardware to sane state */
- rpx_iic_init(&rpx_data);
-
- if (i2c_8xx_add_bus(&rpx_ops) < 0) {
- printk("i2c-rpx: Unable to register with I2C\n");
- return -ENODEV;
- }
-
- return 0;
-}
-
-void __exit i2c_rpx_exit(void)
-{
- i2c_8xx_del_bus(&rpx_ops);
-}
-
-MODULE_AUTHOR("Dan Malek <dmalek@jlc.net>");
-MODULE_DESCRIPTION("I2C-Bus adapter routines for MPC8xx boards");
-
-module_init(i2c_rpx_init);
-module_exit(i2c_rpx_exit);