diff options
Diffstat (limited to 'recipes/linux/linux-mtx-2-2.4.27/16-i2c.patch')
-rw-r--r-- | recipes/linux/linux-mtx-2-2.4.27/16-i2c.patch | 7482 |
1 files changed, 7482 insertions, 0 deletions
diff --git a/recipes/linux/linux-mtx-2-2.4.27/16-i2c.patch b/recipes/linux/linux-mtx-2-2.4.27/16-i2c.patch new file mode 100644 index 0000000000..cec737bdfe --- /dev/null +++ b/recipes/linux/linux-mtx-2-2.4.27/16-i2c.patch @@ -0,0 +1,7482 @@ +--- linux-old/Documentation/Configure.help Mon Dec 13 16:57:33 2004 ++++ linux/Documentation/Configure.help Mon Dec 13 19:26:23 2004 +@@ -19347,6 +19347,16 @@ + <file:Documentation/modules.txt>. + The module will be called i2c-velleman.o. + ++Basic I2C on Parallel Port adapter ++CONFIG_I2C_PPORT ++ This supports directly connecting I2C devices to the parallel port. ++ See <file:Documentation/i2c/i2c-pport> for more information. ++ ++ This driver is also available as a module. If you want to compile ++ it as a module, say M here and read ++ <file:Documentation/modules.txt>. ++ The module will be called i2c-pport.o. ++ + I2C PCF 8584 interfaces + CONFIG_I2C_ALGOPCF + This allows you to use a range of I2C adapters called PCF adapters. +@@ -19368,6 +19378,15 @@ + <file:Documentation/modules.txt>. + The module will be called i2c-elektor.o. + ++PCF on the EPP Parallel Port ++CONFIG_I2C_PCFEPP ++ This supports the PCF8584 connected to the parallel port. ++ ++ This driver is also available as a module. If you want to compile ++ it as a module, say M here and read ++ <file:Documentation/modules.txt>. ++ The module will be called i2c-pcf-epp.o. ++ + ITE I2C Algorithm + CONFIG_ITE_I2C_ALGO + This supports the use the ITE8172 I2C interface found on some MIPS +@@ -19405,6 +19424,51 @@ + Supports the SGI interfaces like the ones found on SGI Indy VINO + or SGI O2 MACE. + ++Motorola 8xx I2C algorithm ++CONFIG_I2C_ALGO8XX ++ This is the algorithm that allows you to use Motorola 8xx I2C adapters. ++ ++ This driver is also available as a module. If you want to compile ++ it as a module, say M here and read ++ <file:Documentation/modules.txt>. ++ The module will be called i2c-algo-8xx.o. ++ ++Motorola 8xx I2C interface ++CONFIG_I2C_RPXLITE ++ This supports the Motorola 8xx I2C device. ++ ++ This driver is also available as a module. If you want to compile ++ it as a module, say M here and read ++ <file:Documentation/modules.txt>. ++ The module will be called i2c-rpx.o. ++ ++IBM 405 I2C algorithm ++CONFIG_I2C_IBM_OCP_ALGO ++ This is the algorithm that allows you to use IBM 405 I2C adapters. ++ ++ This driver is also available as a module. If you want to compile ++ it as a module, say M here and read ++ <file:Documentation/modules.txt>. ++ The module will be called i2c-algo-ibm_ocp.o. ++ ++IBM 405 I2C interface ++CONFIG_I2C_IBM_OCP_ADAP ++ This supports the IBM 405 I2C device. ++ ++ This driver is also available as a module. If you want to compile ++ it as a module, say M here and read ++ <file:Documentation/modules.txt>. ++ The module will be called i2c-adap-ibm_ocp.o. ++ ++StrongARM SA-1110 interface ++CONFIG_I2C_FRODO ++ This supports the StrongARM SA-1110 Development Board. ++ ++ This driver is also available as a module. If you want to compile ++ it as a module, say M here and read ++ <file:Documentation/modules.txt>. ++ The module will be called i2c-frodo.o. ++ + I2C device interface + CONFIG_I2C_CHARDEV + Say Y here to use i2c-* device files, usually found in the /dev +--- linux-old/Documentation/i2c/dev-interface Mon Dec 22 22:44:34 2003 ++++ linux/Documentation/i2c/dev-interface Mon Dec 13 19:26:23 2004 +@@ -89,6 +89,11 @@ + Selects ten bit addresses if select not equals 0, selects normal 7 bit + addresses if select equals 0. Default 0. + ++ioctl(file,I2C_PEC,long select) ++ Selects SMBus PEC (packet error checking) generation and verification ++ if select not equals 0, disables if select equals 0. Default 0. ++ Used only for SMBus transactions. ++ + ioctl(file,I2C_FUNCS,unsigned long *funcs) + Gets the adapter functionality and puts it in *funcs. + +--- linux-old/Documentation/i2c/i2c-pport Thu Jan 1 00:00:00 1970 ++++ linux/Documentation/i2c/i2c-pport Mon Dec 13 19:26:24 2004 +@@ -0,0 +1,67 @@ ++Parallel Port Adapters ++---------------------- ++If you are installing parallel port adapters it means you are probably messing ++around with wires and IC's and the like. If you have purchased a card that ++provides an external i2c/smbus this will require combined algorithm and ++adapter code in a single module. ++If you are doing it yourself by using the parallel port there ++are basically 2 options. ++ ++1) Using the parallel port and using the i2c-pport adapter module and the ++i2c-algo-bit algorithm module together to enable you to wire up your parallel ++port to act as an i2c/smbus. This provides a bus that will enable most ++sensors to work but doesn't support the entire i2c/smbus capability. ++ ++2) Using the parallel port to interface to a Philips PCF8584 parallel to i2c ++adapter chip. You will need to build a bit of a circuit to do this. This ++configuration needs the i2c-pcf-epp adapter module and the i2c-algo-pcf ++algorithm module. This support almost all of the i2c/smbus capabilities. ++ ++ ++i2c-pport Documentation ++----------------------- ++This is a primitive parallel port driver for the i2c bus, which exploits ++features of modern bidirectional parallel ports. ++ ++Bidirectional ports have particular bits connected in following way: ++ ++ | ++ /-----| R ++ --o| |-----| ++ read \-----| /------- Out pin ++ |/ ++ - -|\ ++ write V ++ | ++ --- ++ ++ ++It means when output is set to 1 we can read the port. Therefore ++we can use 2 pins of parallel port as SDA and SCL for i2c bus. It ++is not necessary to add any external - additional parts, we can ++read and write the same port simultaneously. ++ I only use register base+2 so it is possible to use all ++8 data bits of parallel port for other applications (I have ++connected EEPROM and LCD display). I do not use bit Enable Bi-directional ++ Port. The only disadvantage is we can only support 5V chips. ++ ++Layout: ++ ++Cannon 25 pin ++ ++SDA - connect to pin 14 (Auto Linefeed) ++SCL - connect to pin 16 (Initialize Printer) ++GND - connect to pin 18-25 +++5V - use external supply (I use 5V from 3.5" floppy connector) ++ ++no pullups requied ++ ++Module parameters: ++ ++base = 0xXXX ++XXX - 278 or 378 ++ ++That's all. ++ ++Daniel Smolik ++marvin@sitour.cz +--- linux-old/Documentation/i2c/i2c-protocol Mon Dec 22 22:44:34 2003 ++++ linux/Documentation/i2c/i2c-protocol Mon Dec 13 19:26:24 2004 +@@ -65,3 +65,12 @@ + need to emit an Rd instead of a Wr, or vice versa, you set this + flag. For example: + S Addr Rd [A] Data [A] Data [A] ... [A] Data [A] P ++ ++ Flags I2C_M_IGNORE_NAK ++ Normally message is interrupted immediately if there is [NA] from the ++ client. Setting this flag treats any [NA] as [A], and all of ++ message is sent. ++ These messages may still fail to SCL lo->hi timeout. ++ ++ Flags I2C_M_NO_RD_ACK ++ In a read message, master A/NA bit is skipped. +--- linux-old/Documentation/i2c/summary Tue Jan 20 15:10:28 2004 ++++ linux/Documentation/i2c/summary Mon Dec 13 19:26:24 2004 +@@ -59,16 +59,16 @@ + i2c-algo-8xx: An algorithm for CPM's I2C device in Motorola 8xx processors (NOT BUILT BY DEFAULT) + i2c-algo-bit: A bit-banging algorithm + i2c-algo-pcf: A PCF 8584 style algorithm +-i2c-algo-ppc405: An algorithm for the I2C device in IBM 405xx processors (NOT BUILT BY DEFAULT) ++i2c-algo-ibm_ocp: An algorithm for the I2C device in IBM 4xx processors (NOT BUILT BY DEFAULT) + + Adapter drivers + --------------- + + i2c-elektor: Elektor ISA card (uses i2c-algo-pcf) + i2c-elv: ELV parallel port adapter (uses i2c-algo-bit) +-i2c-pcf-epp: PCF8584 on a EPP parallel port (uses i2c-algo-pcf) (BROKEN - missing i2c-pcf-epp.h) ++i2c-pcf-epp: PCF8584 on a EPP parallel port (uses i2c-algo-pcf) (NOT mkpatched) + i2c-philips-par: Philips style parallel port adapter (uses i2c-algo-bit) +-i2c-ppc405: IBM 405xx processor I2C device (uses i2c-algo-ppc405) (NOT BUILT BY DEFAULT) ++i2c-adap-ibm_ocp: IBM 4xx processor I2C device (uses i2c-algo-ibm_ocp) (NOT BUILT BY DEFAULT) + i2c-pport: Primitive parallel port adapter (uses i2c-algo-bit) + i2c-rpx: RPX board Motorola 8xx I2C device (uses i2c-algo-8xx) (NOT BUILT BY DEFAULT) + i2c-velleman: Velleman K8000 parallel port adapter (uses i2c-algo-bit) +--- linux-old/Documentation/i2c/writing-clients Mon Dec 22 22:44:34 2003 ++++ linux/Documentation/i2c/writing-clients Mon Dec 13 19:26:25 2004 +@@ -24,24 +24,24 @@ + routines, a client structure specific information like the actual I2C + address. + +- struct i2c_driver foo_driver +- { +- /* name */ "Foo version 2.3 and later driver", +- /* id */ I2C_DRIVERID_FOO, +- /* flags */ I2C_DF_NOTIFY, +- /* attach_adapter */ &foo_attach_adapter, +- /* detach_client */ &foo_detach_client, +- /* command */ &foo_command, /* May be NULL */ +- /* inc_use */ &foo_inc_use, /* May be NULL */ +- /* dec_use */ &foo_dec_use /* May be NULL */ +- } ++static struct i2c_driver foo_driver = { ++ .owner = THIS_MODULE, ++ .name = "Foo version 2.3 driver", ++ .id = I2C_DRIVERID_FOO, /* from i2c-id.h, optional */ ++ .flags = I2C_DF_NOTIFY, ++ .attach_adapter = &foo_attach_adapter, ++ .detach_client = &foo_detach_client, ++ .command = &foo_command /* may be NULL */ ++} + + The name can be chosen freely, and may be upto 40 characters long. Please + use something descriptive here. + +-The id should be a unique ID. The range 0xf000 to 0xffff is reserved for +-local use, and you can use one of those until you start distributing the +-driver. Before you do that, contact the i2c authors to get your own ID(s). ++If used, the id should be a unique ID. The range 0xf000 to 0xffff is ++reserved for local use, and you can use one of those until you start ++distributing the driver, at which time you should contact the i2c authors ++to get your own ID(s). Note that most of the time you don't need an ID ++at all so you can just omit it. + + Don't worry about the flags field; just put I2C_DF_NOTIFY into it. This + means that your driver will be notified when new adapters are found. +@@ -50,43 +50,8 @@ + All other fields are for call-back functions which will be explained + below. + +- +-Module usage count +-================== +- +-If your driver can also be compiled as a module, there are moments at +-which the module can not be removed from memory. For example, when you +-are doing a lengthy transaction, or when you create a /proc directory, +-and some process has entered that directory (this last case is the +-main reason why these call-backs were introduced). +- +-To increase or decrease the module usage count, you can use the +-MOD_{INC,DEC}_USE_COUNT macros. They must be called from the module +-which needs to get its usage count changed; that is why each driver +-module has to implement its own callback. +- +- void foo_inc_use (struct i2c_client *client) +- { +- #ifdef MODULE +- MOD_INC_USE_COUNT; +- #endif +- } +- +- void foo_dec_use (struct i2c_client *client) +- { +- #ifdef MODULE +- MOD_DEC_USE_COUNT; +- #endif +- } +- +-Do not call these call-back functions directly; instead, use one of the +-following functions defined in i2c.h: +- void i2c_inc_use_client(struct i2c_client *); +- void i2c_dec_use_client(struct i2c_client *); +- +-You should *not* increase the module count just because a device is +-detected and a client created. This would make it impossible to remove +-an adapter driver! ++There use to be two additional fields in this structure, inc_use et dec_use, ++for module usage count, but these fields were obsoleted and removed. + + + Extra client data +--- linux-old/drivers/i2c/i2c-adap-ibm_ocp.c Thu Jan 1 00:00:00 1970 ++++ linux/drivers/i2c/i2c-adap-ibm_ocp.c Mon Dec 13 19:26:26 2004 +@@ -0,0 +1,346 @@ ++/* ++ ------------------------------------------------------------------------- ++ i2c-adap-ibm_ocp.c i2c-hw access for the IIC peripheral on the IBM PPC 405 ++ ------------------------------------------------------------------------- ++ ++ Ian DaSilva, MontaVista Software, Inc. ++ idasilva@mvista.com or source@mvista.com ++ ++ Copyright 2000 MontaVista Software Inc. ++ ++ Changes made to support the IIC peripheral on the IBM PPC 405 ++ ++ ++ ---------------------------------------------------------------------------- ++ 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 ++ ++ 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. ++ ++ 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. ++ ---------------------------------------------------------------------------- ++ ++ History: 01/20/12 - Armin ++ akuster@mvista.com ++ ported up to 2.4.16+ ++ ++ Version 02/03/25 - Armin ++ converted to ocp format ++ removed commented out or #if 0 code ++ ++ TODO: convert to ocp_register ++ add PM hooks ++ ++*/ ++ ++ ++#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 <linux/i2c.h> ++#include <linux/i2c-algo-ibm_ocp.h> ++#include <asm/irq.h> ++#include <asm/io.h> ++#include <asm/ocp.h> ++ ++/* ++ * This next section is configurable, and it is used to set the number ++ * of i2c controllers in the system. The default number of instances is 1, ++ * however, this should be changed to reflect your system's configuration. ++ */ ++ ++/* ++ * The STB03xxx, with a PPC405 core, has two i2c controllers. ++ */ ++//(sizeof(IIC_ADDR)/sizeof(struct iic_regs)) ++extern iic_t *IIC_ADDR[]; ++static struct iic_ibm iic_ibmocp_adaps[IIC_NUMS][5]; ++ ++static struct i2c_algo_iic_data *iic_ibmocp_data[IIC_NUMS]; ++static struct i2c_adapter *iic_ibmocp_ops[IIC_NUMS]; ++ ++static int i2c_debug=0; ++static wait_queue_head_t iic_wait[IIC_NUMS]; ++static int iic_pending; ++static spinlock_t irq_driver_lock = SPIN_LOCK_UNLOCKED; ++ ++ ++/* ----- 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 ---------------------------------------------- */ ++ ++// ++// Description: Write a byte to IIC hardware ++// ++static void iic_ibmocp_setbyte(void *data, int ctl, int val) ++{ ++ // writeb resolves to a write to the specified memory location ++ // plus a call to eieio. eieio ensures that all instructions ++ // preceding it are completed before any further stores are ++ // completed. ++ // Delays at this level (to protect writes) are not needed here. ++ writeb(val, ctl); ++} ++ ++ ++// ++// Description: Read a byte from IIC hardware ++// ++static int iic_ibmocp_getbyte(void *data, int ctl) ++{ ++ int val; ++ ++ val = readb(ctl); ++ return (val); ++} ++ ++ ++// ++// Description: 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_ibmocp_getown(void *data) ++{ ++ return(((struct iic_ibm *)(data))->iic_own); ++} ++ ++ ++// ++// Description: Return the clock rate ++// ++static int iic_ibmocp_getclock(void *data) ++{ ++ return(((struct iic_ibm *)(data))->iic_clock); ++} ++ ++ ++ ++// ++// Description: Put this process to sleep. We will wake up when the ++// IIC controller interrupts. ++// ++static void iic_ibmocp_waitforpin(void *data) { ++ ++ int timeout = 2; ++ struct iic_ibm *priv_data = data; ++ ++ // ++ // 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 (priv_data->iic_irq > 0) { ++ spin_lock_irq(&irq_driver_lock); ++ if (iic_pending == 0) { ++ interruptible_sleep_on_timeout(&(iic_wait[priv_data->index]), timeout*HZ ); ++ } else ++ iic_pending = 0; ++ spin_unlock_irq(&irq_driver_lock); ++ } else { ++ // ++ // If interrupts are not enabled then delay for a reasonable amount ++ // of time and return. We expect that by time we return to the calling ++ // function that the IIC has finished our requested transaction and ++ // the status bit reflects this. ++ // ++ // udelay is probably not the best choice for this since it is ++ // the equivalent of a busy wait ++ // ++ udelay(100); ++ } ++ //printk("iic_ibmocp_waitforpin: exitting\n"); ++} ++ ++ ++// ++// Description: The registered interrupt handler ++// ++static void iic_ibmocp_handler(int this_irq, void *dev_id, struct pt_regs *regs) ++{ ++ int ret; ++ struct iic_regs *iic; ++ struct iic_ibm *priv_data = dev_id; ++ iic = (struct iic_regs *) priv_data->iic_base; ++ iic_pending = 1; ++ DEB2(printk("iic_ibmocp_handler: in interrupt handler\n")); ++ // Read status register ++ ret = readb((int) &(iic->sts)); ++ DEB2(printk("iic_ibmocp_handler: status = %x\n", ret)); ++ // Clear status register. See IBM PPC 405 reference manual for details ++ writeb(0x0a, (int) &(iic->sts)); ++ wake_up_interruptible(&(iic_wait[priv_data->index])); ++} ++ ++ ++// ++// Description: This function is very hardware dependent. First, we lock ++// the region of memory where out registers exist. Next, we request our ++// interrupt line and register its associated handler. Our IIC peripheral ++// uses interrupt number 2, as specified by the 405 reference manual. ++// ++static int iic_hw_resrc_init(int instance) ++{ ++ ++ DEB(printk("iic_hw_resrc_init: Physical Base address: 0x%x\n", (u32) IIC_ADDR[instance] )); ++ iic_ibmocp_adaps[instance]->iic_base = (u32)ioremap((unsigned long)IIC_ADDR[instance],PAGE_SIZE); ++ ++ DEB(printk("iic_hw_resrc_init: ioremapped base address: 0x%x\n", iic_ibmocp_adaps[instance]->iic_base)); ++ ++ if (iic_ibmocp_adaps[instance]->iic_irq > 0) { ++ ++ if (request_irq(iic_ibmocp_adaps[instance]->iic_irq, iic_ibmocp_handler, ++ 0, "IBM OCP IIC", iic_ibmocp_adaps[instance]) < 0) { ++ printk(KERN_ERR "iic_hw_resrc_init: Request irq%d failed\n", ++ iic_ibmocp_adaps[instance]->iic_irq); ++ iic_ibmocp_adaps[instance]->iic_irq = 0; ++ } else { ++ DEB3(printk("iic_hw_resrc_init: Enabled interrupt\n")); ++ } ++ } ++ return 0; ++} ++ ++ ++// ++// Description: Release irq and memory ++// ++static void iic_ibmocp_release(void) ++{ ++ int i; ++ ++ for(i=0; i<IIC_NUMS; i++) { ++ struct iic_ibm *priv_data = (struct iic_ibm *)iic_ibmocp_data[i]->data; ++ if (priv_data->iic_irq > 0) { ++ disable_irq(priv_data->iic_irq); ++ free_irq(priv_data->iic_irq, 0); ++ } ++ kfree(iic_ibmocp_data[i]); ++ kfree(iic_ibmocp_ops[i]); ++ } ++} ++ ++ ++// ++// Description: Called when the module is loaded. This function starts the ++// cascade of calls up through the heirarchy of i2c modules (i.e. up to the ++// algorithm layer and into to the core layer) ++// ++static int __init iic_ibmocp_init(void) ++{ ++ int i; ++ ++ printk(KERN_INFO "iic_ibmocp_init: IBM on-chip iic adapter module\n"); ++ ++ for(i=0; i<IIC_NUMS; i++) { ++ iic_ibmocp_data[i] = kmalloc(sizeof(struct i2c_algo_iic_data),GFP_KERNEL); ++ if(iic_ibmocp_data[i] == NULL) { ++ return -ENOMEM; ++ } ++ memset(iic_ibmocp_data[i], 0, sizeof(struct i2c_algo_iic_data)); ++ ++ switch (i) { ++ case 0: ++ iic_ibmocp_adaps[i]->iic_irq = IIC_IRQ(0); ++ break; ++ case 1: ++ iic_ibmocp_adaps[i]->iic_irq = IIC_IRQ(1); ++ break; ++ } ++ iic_ibmocp_adaps[i]->iic_clock = IIC_CLOCK; ++ iic_ibmocp_adaps[i]->iic_own = IIC_OWN; ++ iic_ibmocp_adaps[i]->index = i; ++ ++ DEB(printk("irq %x\n", iic_ibmocp_adaps[i]->iic_irq)); ++ DEB(printk("clock %x\n", iic_ibmocp_adaps[i]->iic_clock)); ++ DEB(printk("own %x\n", iic_ibmocp_adaps[i]->iic_own)); ++ DEB(printk("index %x\n", iic_ibmocp_adaps[i]->index)); ++ ++ ++ iic_ibmocp_data[i]->data = (struct iic_regs *)iic_ibmocp_adaps[i]; ++ iic_ibmocp_data[i]->setiic = iic_ibmocp_setbyte; ++ iic_ibmocp_data[i]->getiic = iic_ibmocp_getbyte; ++ iic_ibmocp_data[i]->getown = iic_ibmocp_getown; ++ iic_ibmocp_data[i]->getclock = iic_ibmocp_getclock; ++ iic_ibmocp_data[i]->waitforpin = iic_ibmocp_waitforpin; ++ iic_ibmocp_data[i]->udelay = 80; ++ iic_ibmocp_data[i]->mdelay = 80; ++ iic_ibmocp_data[i]->timeout = HZ; ++ ++ iic_ibmocp_ops[i] = kmalloc(sizeof(struct i2c_adapter), GFP_KERNEL); ++ if(iic_ibmocp_ops[i] == NULL) { ++ return -ENOMEM; ++ } ++ memset(iic_ibmocp_ops[i], 0, sizeof(struct i2c_adapter)); ++ strcpy(iic_ibmocp_ops[i]->name, "IBM OCP IIC adapter"); ++ iic_ibmocp_ops[i]->owner = THIS_MODULE; ++ iic_ibmocp_ops[i]->id = I2C_HW_OCP; ++ iic_ibmocp_ops[i]->algo = NULL; ++ iic_ibmocp_ops[i]->algo_data = iic_ibmocp_data[i]; ++ ++ ++ init_waitqueue_head(&(iic_wait[i])); ++ if (iic_hw_resrc_init(i) == 0) { ++ if (i2c_ocp_add_bus(iic_ibmocp_ops[i]) < 0) ++ return -ENODEV; ++ } else { ++ return -ENODEV; ++ } ++ DEB(printk(KERN_INFO "iic_ibmocp_init: found device at %#x.\n\n", iic_ibmocp_adaps[i]->iic_base)); ++ } ++ return 0; ++} ++ ++ ++static void __exit iic_ibmocp_exit(void) ++{ ++ int i; ++ ++ for(i=0; i<IIC_NUMS; i++) { ++ i2c_ocp_del_bus(iic_ibmocp_ops[i]); ++ } ++ iic_ibmocp_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 PPC 405 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"); ++ ++ ++module_init(iic_ibmocp_init); ++module_exit(iic_ibmocp_exit); +--- linux-old/drivers/i2c/i2c-algo-8xx.c Thu Jan 1 00:00:00 1970 ++++ linux/drivers/i2c/i2c-algo-8xx.c Mon Dec 13 19:26:27 2004 +@@ -0,0 +1,616 @@ ++/* ++ * i2c-algo-8xx.c i2x driver algorithms for MPC8XX CPM ++ * Copyright (c) 1999 Dan Malek (dmalek@jlc.net). ++ * ++ 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. ++ * ++ * moved into proper i2c interface; separated out platform specific ++ * parts into i2c-rpx.c ++ * Brad Parker (brad@heeltoe.com) ++ */ ++ ++// XXX todo ++// timeout sleep? ++ ++/* $Id: i2c-algo-8xx.c,v 1.14 2003/07/25 07:56:42 khali Exp $ */ ++ ++#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 <linux/i2c-algo-8xx.h> ++#include <asm/mpc8xx.h> ++#include <asm/commproc.h> ++ ++ ++#define CPM_MAX_READ 513 ++/* #define I2C_CHIP_ERRATA */ /* Try uncomment this if you have an older CPU(earlier than rev D4) */ ++static wait_queue_head_t iic_wait; ++static ushort r_tbase, r_rbase; ++ ++int cpm_debug = 0; ++ ++static void ++cpm_iic_interrupt(void *dev_id, struct pt_regs *regs) ++{ ++ volatile i2c8xx_t *i2c = (i2c8xx_t *)dev_id; ++ if (cpm_debug > 1) ++ printk("cpm_iic_interrupt(dev_id=%p)\n", dev_id); ++#if 0 ++ /* Chip errata, clear enable. This is not needed on rev D4 CPUs */ ++ /* This should probably be removed and replaced by I2C_CHIP_ERRATA stuff */ ++ /* Someone with a buggy CPU needs to confirm that */ ++ i2c->i2c_i2mod &= ~1; ++#endif ++ /* Clear interrupt. ++ */ ++ i2c->i2c_i2cer = 0xff; ++ ++ /* Get 'me going again. ++ */ ++ wake_up_interruptible(&iic_wait); ++} ++ ++static void ++cpm_iic_init(struct i2c_algo_8xx_data *cpm) ++{ ++ volatile iic_t *iip = cpm->iip; ++ volatile i2c8xx_t *i2c = cpm->i2c; ++ unsigned char brg; ++ bd_t *bd = (bd_t *)__res; ++ ++ if (cpm_debug) printk(KERN_DEBUG "cpm_iic_init()\n"); ++ ++ /* Initialize the parameter ram. ++ * We need to make sure many things are initialized to zero, ++ * especially in the case of a microcode patch. ++ */ ++ iip->iic_rstate = 0; ++ iip->iic_rdp = 0; ++ iip->iic_rbptr = 0; ++ iip->iic_rbc = 0; ++ iip->iic_rxtmp = 0; ++ iip->iic_tstate = 0; ++ iip->iic_tdp = 0; ++ iip->iic_tbptr = 0; ++ iip->iic_tbc = 0; ++ iip->iic_txtmp = 0; ++ ++ /* Set up the IIC parameters in the parameter ram. ++ */ ++ iip->iic_tbase = r_tbase = cpm->dp_addr; ++ iip->iic_rbase = r_rbase = cpm->dp_addr + sizeof(cbd_t)*2; ++ ++ iip->iic_tfcr = SMC_EB; ++ iip->iic_rfcr = SMC_EB; ++ ++ /* Set maximum receive size. ++ */ ++ iip->iic_mrblr = CPM_MAX_READ; ++ ++ /* Initialize Tx/Rx parameters. ++ */ ++ if (cpm->reloc == 0) { ++ volatile cpm8xx_t *cp = cpm->cp; ++ ++ cp->cp_cpcr = ++ mk_cr_cmd(CPM_CR_CH_I2C, CPM_CR_INIT_TRX) | CPM_CR_FLG; ++ while (cp->cp_cpcr & CPM_CR_FLG); ++ } else { ++ iip->iic_rbptr = iip->iic_rbase; ++ iip->iic_tbptr = iip->iic_tbase; ++ iip->iic_rstate = 0; ++ iip->iic_tstate = 0; ++ } ++ ++ /* Select an arbitrary address. Just make sure it is unique. ++ */ ++ i2c->i2c_i2add = 0xfe; ++ ++ /* Make clock run at 60 KHz. ++ */ ++ brg = (unsigned char) (bd->bi_intfreq/(32*2*60000) -3); ++ i2c->i2c_i2brg = brg; ++ ++ i2c->i2c_i2mod = 0x00; ++ i2c->i2c_i2com = 0x01; /* Master mode */ ++ ++ /* Disable interrupts. ++ */ ++ i2c->i2c_i2cmr = 0; ++ i2c->i2c_i2cer = 0xff; ++ ++ init_waitqueue_head(&iic_wait); ++ ++ /* Install interrupt handler. ++ */ ++ if (cpm_debug) { ++ printk ("%s[%d] Install ISR for IRQ %d\n", ++ __func__,__LINE__, CPMVEC_I2C); ++ } ++ (*cpm->setisr)(CPMVEC_I2C, cpm_iic_interrupt, (void *)i2c); ++} ++ ++ ++static int ++cpm_iic_shutdown(struct i2c_algo_8xx_data *cpm) ++{ ++ volatile i2c8xx_t *i2c = cpm->i2c; ++ ++ /* Shut down IIC. ++ */ ++ i2c->i2c_i2mod &= ~1; ++ i2c->i2c_i2cmr = 0; ++ i2c->i2c_i2cer = 0xff; ++ ++ return(0); ++} ++ ++static void ++cpm_reset_iic_params(volatile iic_t *iip) ++{ ++ iip->iic_tbase = r_tbase; ++ iip->iic_rbase = r_rbase; ++ ++ iip->iic_tfcr = SMC_EB; ++ iip->iic_rfcr = SMC_EB; ++ ++ iip->iic_mrblr = CPM_MAX_READ; ++ ++ iip->iic_rstate = 0; ++ iip->iic_rdp = 0; ++ iip->iic_rbptr = iip->iic_rbase; ++ iip->iic_rbc = 0; ++ iip->iic_rxtmp = 0; ++ iip->iic_tstate = 0; ++ iip->iic_tdp = 0; ++ iip->iic_tbptr = iip->iic_tbase; ++ iip->iic_tbc = 0; ++ iip->iic_txtmp = 0; ++} ++ ++#define BD_SC_NAK ((ushort)0x0004) /* NAK - did not respond */ ++#define BD_SC_OV ((ushort)0x0002) /* OV - receive overrun */ ++#define CPM_CR_CLOSE_RXBD ((ushort)0x0007) ++ ++static void force_close(struct i2c_algo_8xx_data *cpm) ++{ ++ volatile i2c8xx_t *i2c = cpm->i2c; ++ if (cpm->reloc == 0) { /* micro code disabled */ ++ volatile cpm8xx_t *cp = cpm->cp; ++ ++ if (cpm_debug) printk("force_close()\n"); ++ cp->cp_cpcr = ++ mk_cr_cmd(CPM_CR_CH_I2C, CPM_CR_CLOSE_RXBD) | ++ CPM_CR_FLG; ++ ++ while (cp->cp_cpcr & CPM_CR_FLG); ++ } ++ i2c->i2c_i2cmr = 0x00; /* Disable all interrupts */ ++ i2c->i2c_i2cer = 0xff; ++} ++ ++ ++/* Read from IIC... ++ * abyte = address byte, with r/w flag already set ++ */ ++static int ++cpm_iic_read(struct i2c_algo_8xx_data *cpm, u_char abyte, char *buf, int count) ++{ ++ volatile iic_t *iip = cpm->iip; ++ volatile i2c8xx_t *i2c = cpm->i2c; ++ volatile cpm8xx_t *cp = cpm->cp; ++ volatile cbd_t *tbdf, *rbdf; ++ u_char *tb; ++ unsigned long flags, tmo; ++ ++ if (count >= CPM_MAX_READ) ++ return -EINVAL; ++ ++ /* check for and use a microcode relocation patch */ ++ if (cpm->reloc) { ++ cpm_reset_iic_params(iip); ++ } ++ ++ tbdf = (cbd_t *)&cp->cp_dpmem[iip->iic_tbase]; ++ rbdf = (cbd_t *)&cp->cp_dpmem[iip->iic_rbase]; ++ ++ /* To read, we need an empty buffer of the proper length. ++ * All that is used is the first byte for address, the remainder ++ * is just used for timing (and doesn't really have to exist). ++ */ ++ tb = cpm->temp; ++ tb = (u_char *)(((uint)tb + 15) & ~15); ++ tb[0] = abyte; /* Device address byte w/rw flag */ ++ ++ flush_dcache_range((unsigned long) tb, (unsigned long) (tb+1)); ++ ++ if (cpm_debug) printk("cpm_iic_read(abyte=0x%x)\n", abyte); ++ ++ tbdf->cbd_bufaddr = __pa(tb); ++ tbdf->cbd_datlen = count + 1; ++ tbdf->cbd_sc = ++ BD_SC_READY | BD_SC_LAST | ++ BD_SC_WRAP | BD_IIC_START; ++ ++ iip->iic_mrblr = count +1; /* prevent excessive read, +1 ++ is needed otherwise will the ++ RXB interrupt come too early */ ++ ++ /* flush will invalidate too. */ ++ flush_dcache_range((unsigned long) buf, (unsigned long) (buf+count)); ++ ++ rbdf->cbd_datlen = 0; ++ rbdf->cbd_bufaddr = __pa(buf); ++ rbdf->cbd_sc = BD_SC_EMPTY | BD_SC_WRAP| BD_SC_INTRPT; ++ if(count > 16){ ++ /* Chip bug, set enable here */ ++ local_irq_save(flags); ++ i2c->i2c_i2cmr = 0x13; /* Enable some interupts */ ++ i2c->i2c_i2cer = 0xff; ++ i2c->i2c_i2mod |= 1; /* Enable */ ++ i2c->i2c_i2com |= 0x80; /* Begin transmission */ ++ ++ /* Wait for IIC transfer */ ++ tmo = interruptible_sleep_on_timeout(&iic_wait,1*HZ); ++ local_irq_restore(flags); ++ } else { /* busy wait for small transfers, its faster */ ++ i2c->i2c_i2cmr = 0x00; /* Disable I2C interupts */ ++ i2c->i2c_i2cer = 0xff; ++ i2c->i2c_i2mod |= 1; /* Enable */ ++ i2c->i2c_i2com |= 0x80; /* Begin transmission */ ++ tmo = jiffies + 1*HZ; ++ while(!(i2c->i2c_i2cer & 0x11 || time_after(jiffies, tmo))); /* Busy wait, with a timeout */ ++ } ++ ++ if (signal_pending(current) || !tmo){ ++ force_close(cpm); ++ if(cpm_debug) ++ printk("IIC read: timeout!\n"); ++ return -EIO; ++ } ++#ifdef I2C_CHIP_ERRATA ++ /* Chip errata, clear enable. This is not needed on rev D4 CPUs. ++ Disabling I2C too early may cause too short stop condition */ ++ udelay(4); ++ i2c->i2c_i2mod &= ~1; ++#endif ++ if (cpm_debug) { ++ printk("tx sc %04x, rx sc %04x\n", ++ tbdf->cbd_sc, rbdf->cbd_sc); ++ } ++ ++ if (tbdf->cbd_sc & BD_SC_READY) { ++ printk("IIC read; complete but tbuf ready\n"); ++ force_close(cpm); ++ printk("tx sc %04x, rx sc %04x\n", ++ tbdf->cbd_sc, rbdf->cbd_sc); ++ } ++ ++ if (tbdf->cbd_sc & BD_SC_NAK) { ++ if (cpm_debug) ++ printk("IIC read; no ack\n"); ++ return -EREMOTEIO; ++ } ++ ++ if (rbdf->cbd_sc & BD_SC_EMPTY) { ++ /* force_close(cpm); */ ++ if (cpm_debug){ ++ printk("IIC read; complete but rbuf empty\n"); ++ printk("tx sc %04x, rx sc %04x\n", ++ tbdf->cbd_sc, rbdf->cbd_sc); ++ } ++ return -EREMOTEIO; ++ } ++ ++ if (rbdf->cbd_sc & BD_SC_OV) { ++ if (cpm_debug) ++ printk("IIC read; Overrun\n"); ++ return -EREMOTEIO;; ++ } ++ ++ if (cpm_debug) printk("read %d bytes\n", rbdf->cbd_datlen); ++ ++ if (rbdf->cbd_datlen < count) { ++ if (cpm_debug) ++ printk("IIC read; short, wanted %d got %d\n", ++ count, rbdf->cbd_datlen); ++ return 0; ++ } ++ ++ return count; ++} ++ ++/* Write to IIC... ++ * addr = address byte, with r/w flag already set ++ */ ++static int ++cpm_iic_write(struct i2c_algo_8xx_data *cpm, u_char abyte, char *buf,int count) ++{ ++ volatile iic_t *iip = cpm->iip; ++ volatile i2c8xx_t *i2c = cpm->i2c; ++ volatile cpm8xx_t *cp = cpm->cp; ++ volatile cbd_t *tbdf; ++ u_char *tb; ++ unsigned long flags, tmo; ++ ++ /* check for and use a microcode relocation patch */ ++ if (cpm->reloc) { ++ cpm_reset_iic_params(iip); ++ } ++ tb = cpm->temp; ++ tb = (u_char *)(((uint)tb + 15) & ~15); ++ *tb = abyte; /* Device address byte w/rw flag */ ++ ++ flush_dcache_range((unsigned long) tb, (unsigned long) (tb+1)); ++ flush_dcache_range((unsigned long) buf, (unsigned long) (buf+count)); ++ ++ if (cpm_debug) printk("cpm_iic_write(abyte=0x%x)\n", abyte); ++ ++ /* set up 2 descriptors */ ++ tbdf = (cbd_t *)&cp->cp_dpmem[iip->iic_tbase]; ++ ++ tbdf[0].cbd_bufaddr = __pa(tb); ++ tbdf[0].cbd_datlen = 1; ++ tbdf[0].cbd_sc = BD_SC_READY | BD_IIC_START; ++ ++ tbdf[1].cbd_bufaddr = __pa(buf); ++ tbdf[1].cbd_datlen = count; ++ tbdf[1].cbd_sc = BD_SC_READY | BD_SC_INTRPT | BD_SC_LAST | BD_SC_WRAP; ++ ++ if(count > 16){ ++ /* Chip bug, set enable here */ ++ local_irq_save(flags); ++ i2c->i2c_i2cmr = 0x13; /* Enable some interupts */ ++ i2c->i2c_i2cer = 0xff; ++ i2c->i2c_i2mod |= 1; /* Enable */ ++ i2c->i2c_i2com |= 0x80; /* Begin transmission */ ++ ++ /* Wait for IIC transfer */ ++ tmo = interruptible_sleep_on_timeout(&iic_wait,1*HZ); ++ local_irq_restore(flags); ++ } else { /* busy wait for small transfers, its faster */ ++ i2c->i2c_i2cmr = 0x00; /* Disable I2C interupts */ ++ i2c->i2c_i2cer = 0xff; ++ i2c->i2c_i2mod |= 1; /* Enable */ ++ i2c->i2c_i2com |= 0x80; /* Begin transmission */ ++ tmo = jiffies + 1*HZ; ++ while(!(i2c->i2c_i2cer & 0x12 || time_after(jiffies, tmo))); /* Busy wait, with a timeout */ ++ } ++ ++ if (signal_pending(current) || !tmo){ ++ force_close(cpm); ++ if(cpm_debug && !tmo) ++ printk("IIC write: timeout!\n"); ++ return -EIO; ++ } ++ ++#if I2C_CHIP_ERRATA ++ /* Chip errata, clear enable. This is not needed on rev D4 CPUs. ++ Disabling I2C too early may cause too short stop condition */ ++ udelay(4); ++ i2c->i2c_i2mod &= ~1; ++#endif ++ if (cpm_debug) { ++ printk("tx0 sc %04x, tx1 sc %04x\n", ++ tbdf[0].cbd_sc, tbdf[1].cbd_sc); ++ } ++ ++ if (tbdf->cbd_sc & BD_SC_NAK) { ++ if (cpm_debug) ++ printk("IIC write; no ack\n"); ++ return 0; ++ } ++ ++ if (tbdf->cbd_sc & BD_SC_READY) { ++ if (cpm_debug) ++ printk("IIC write; complete but tbuf ready\n"); ++ return 0; ++ } ++ ++ return count; ++} ++ ++/* See if an IIC address exists.. ++ * addr = 7 bit address, unshifted ++ */ ++static int ++cpm_iic_tryaddress(struct i2c_algo_8xx_data *cpm, int addr) ++{ ++ volatile iic_t *iip = cpm->iip; ++ volatile i2c8xx_t *i2c = cpm->i2c; ++ volatile cpm8xx_t *cp = cpm->cp; ++ volatile cbd_t *tbdf, *rbdf; ++ u_char *tb; ++ unsigned long flags, len, tmo; ++ ++ if (cpm_debug > 1) ++ printk("cpm_iic_tryaddress(cpm=%p,addr=%d)\n", cpm, addr); ++ ++ /* check for and use a microcode relocation patch */ ++ if (cpm->reloc) { ++ cpm_reset_iic_params(iip); ++ } ++ ++ if (cpm_debug && addr == 0) { ++ printk("iip %p, dp_addr 0x%x\n", cpm->iip, cpm->dp_addr); ++ printk("iic_tbase %d, r_tbase %d\n", iip->iic_tbase, r_tbase); ++ } ++ ++ tbdf = (cbd_t *)&cp->cp_dpmem[iip->iic_tbase]; ++ rbdf = (cbd_t *)&cp->cp_dpmem[iip->iic_rbase]; ++ ++ tb = cpm->temp; ++ tb = (u_char *)(((uint)tb + 15) & ~15); ++ ++ /* do a simple read */ ++ tb[0] = (addr << 1) | 1; /* device address (+ read) */ ++ len = 2; ++ ++ flush_dcache_range((unsigned long) tb, (unsigned long) (tb+2)); ++ ++ tbdf->cbd_bufaddr = __pa(tb); ++ tbdf->cbd_datlen = len; ++ tbdf->cbd_sc = ++ BD_SC_READY | BD_SC_LAST | ++ BD_SC_WRAP | BD_IIC_START; ++ ++ rbdf->cbd_datlen = 0; ++ rbdf->cbd_bufaddr = __pa(tb+2); ++ rbdf->cbd_sc = BD_SC_EMPTY | BD_SC_WRAP | BD_SC_INTRPT; ++ ++ local_irq_save(flags); ++ i2c->i2c_i2cmr = 0x13; /* Enable some interupts */ ++ i2c->i2c_i2cer = 0xff; ++ i2c->i2c_i2mod |= 1; /* Enable */ ++ i2c->i2c_i2com |= 0x80; /* Begin transmission */ ++ ++ if (cpm_debug > 1) printk("about to sleep\n"); ++ ++ /* wait for IIC transfer */ ++ tmo = interruptible_sleep_on_timeout(&iic_wait,1*HZ); ++ local_irq_restore(flags); ++ ++#ifdef I2C_CHIP_ERRATA ++ /* Chip errata, clear enable. This is not needed on rev D4 CPUs. ++ Disabling I2C too early may cause too short stop condition */ ++ udelay(4); ++ i2c->i2c_i2mod &= ~1; ++#endif ++ ++ if (signal_pending(current) || !tmo){ ++ force_close(cpm); ++ if(cpm_debug && !tmo) ++ printk("IIC tryaddress: timeout!\n"); ++ return -EIO; ++ } ++ ++ if (cpm_debug > 1) printk("back from sleep\n"); ++ ++ if (tbdf->cbd_sc & BD_SC_NAK) { ++ if (cpm_debug > 1) printk("IIC try; no ack\n"); ++ return 0; ++ } ++ ++ if (tbdf->cbd_sc & BD_SC_READY) { ++ printk("IIC try; complete but tbuf ready\n"); ++ } ++ ++ return 1; ++} ++ ++static int cpm_xfer(struct i2c_adapter *adap, ++ struct i2c_msg msgs[], ++ int num) ++{ ++ struct i2c_algo_8xx_data *cpm = adap->algo_data; ++ struct i2c_msg *pmsg; ++ int i, ret; ++ u_char addr; ++ ++ for (i = 0; i < num; i++) { ++ pmsg = &msgs[i]; ++ ++ if (cpm_debug) ++ printk("i2c-algo-8xx.o: " ++ "#%d addr=0x%x flags=0x%x len=%d\n buf=%lx\n", ++ i, pmsg->addr, pmsg->flags, pmsg->len, (unsigned long)pmsg->buf); ++ ++ addr = pmsg->addr << 1; ++ if (pmsg->flags & I2C_M_RD ) ++ addr |= 1; ++ if (pmsg->flags & I2C_M_REV_DIR_ADDR ) ++ addr ^= 1; ++ ++ if (!(pmsg->flags & I2C_M_NOSTART)) { ++ } ++ if (pmsg->flags & I2C_M_RD ) { ++ /* read bytes into buffer*/ ++ ret = cpm_iic_read(cpm, addr, pmsg->buf, pmsg->len); ++ if (cpm_debug) ++ printk("i2c-algo-8xx.o: read %d bytes\n", ret); ++ if (ret < pmsg->len ) { ++ return (ret<0)? ret : -EREMOTEIO; ++ } ++ } else { ++ /* write bytes from buffer */ ++ ret = cpm_iic_write(cpm, addr, pmsg->buf, pmsg->len); ++ if (cpm_debug) ++ printk("i2c-algo-8xx.o: wrote %d\n", ret); ++ if (ret < pmsg->len ) { ++ return (ret<0) ? ret : -EREMOTEIO; ++ } ++ } ++ } ++ return (num); ++} ++ ++static u32 cpm_func(struct i2c_adapter *adap) ++{ ++ return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR | ++ I2C_FUNC_PROTOCOL_MANGLING; ++} ++ ++/* -----exported algorithm data: ------------------------------------- */ ++ ++static struct i2c_algorithm cpm_algo = { ++ .owner = THIS_MODULE, ++ .name = "MPC8xx CPM algorithm", ++ .id = I2C_ALGO_MPC8XX, ++ .master_xfer = cpm_xfer, ++ .functionality = cpm_func, ++}; ++ ++/* ++ * registering functions to load algorithms at runtime ++ */ ++int i2c_8xx_add_bus(struct i2c_adapter *adap) ++{ ++ int i; ++ struct i2c_algo_8xx_data *cpm = adap->algo_data; ++ ++ if (cpm_debug) ++ printk("i2c-algo-8xx.o: hw routines for %s registered.\n", ++ adap->name); ++ ++ /* register new adapter to i2c module... */ ++ ++ adap->id |= cpm_algo.id; ++ adap->algo = &cpm_algo; ++ ++ i2c_add_adapter(adap); ++ cpm_iic_init(cpm); ++} ++ ++ ++int i2c_8xx_del_bus(struct i2c_adapter *adap) ++{ ++ struct i2c_algo_8xx_data *cpm = adap->algo_data; ++ ++ cpm_iic_shutdown(cpm); ++ ++ return i2c_del_adapter(adap); ++} ++ ++EXPORT_SYMBOL(i2c_8xx_add_bus); ++EXPORT_SYMBOL(i2c_8xx_del_bus); ++ ++MODULE_AUTHOR("Brad Parker <brad@heeltoe.com>"); ++MODULE_DESCRIPTION("I2C-Bus MPC8XX algorithm"); ++MODULE_LICENSE("GPL"); +--- linux-old/include/linux/i2c-algo-8xx.h Thu Jan 1 00:00:00 1970 ++++ linux/include/linux/i2c-algo-8xx.h Mon Dec 13 19:26:27 2004 +@@ -0,0 +1,43 @@ ++/* ------------------------------------------------------------------------- */ ++/* i2c-algo-8xx.h i2c driver algorithms for MPX8XX CPM */ ++/* ++ 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. */ ++/* ------------------------------------------------------------------------- */ ++ ++/* $Id: i2c-algo-8xx.h,v 1.7 2003/08/01 20:56:38 khali Exp $ */ ++ ++#ifndef _LINUX_I2C_ALGO_8XX_H ++#define _LINUX_I2C_ALGO_8XX_H ++ ++#include "asm/commproc.h" ++ ++struct i2c_algo_8xx_data { ++ uint dp_addr; ++ int reloc; ++ volatile i2c8xx_t *i2c; ++ volatile iic_t *iip; ++ volatile cpm8xx_t *cp; ++ ++ int (*setisr) (int irq, ++ void (*func)(void *, void *), ++ void *data); ++ ++ u_char temp[513]; ++}; ++ ++int i2c_8xx_add_bus(struct i2c_adapter *); ++int i2c_8xx_del_bus(struct i2c_adapter *); ++ ++#endif /* _LINUX_I2C_ALGO_8XX_H */ +--- linux-old/drivers/i2c/i2c-algo-bit.c Tue Jan 20 15:10:31 2004 ++++ linux/drivers/i2c/i2c-algo-bit.c Mon Dec 13 19:26:27 2004 +@@ -18,24 +18,22 @@ + 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> */ ++/* With some changes from Frodo Looijaard <frodol@dds.nl>, Kyösti Mälkki ++ <kmalkki@cc.hut.fi> and Jean Delvare <khali@linux-fr.org> */ + +-/* $Id: i2c-algo-bit.c,v 1.30 2001/07/29 02:44:25 mds Exp $ */ ++/* $Id: i2c-algo-bit.c,v 1.50 2003/12/22 20:03:39 khali Exp $ */ + + #include <linux/kernel.h> + #include <linux/module.h> + #include <linux/delay.h> + #include <linux/slab.h> + #include <linux/init.h> +-#include <asm/uaccess.h> +-#include <linux/ioport.h> + #include <linux/errno.h> + #include <linux/sched.h> +- + #include <linux/i2c.h> + #include <linux/i2c-algo-bit.h> + ++ + /* ----- global defines ----------------------------------------------- */ + #define DEB(x) if (i2c_debug>=1) x; + #define DEB2(x) if (i2c_debug>=2) x; +@@ -43,27 +41,13 @@ + #define DEBPROTO(x) if (i2c_debug>=9) { x; } + /* debug the protocol by showing transferred bits */ + +-/* debugging - slow down transfer to have a look at the data .. */ +-/* I use this with two leds&resistors, each one connected to sda,scl */ +-/* respectively. This makes sure that the algorithm works. Some chips */ +-/* might not like this, as they have an internal timeout of some mils */ +-/* +-#define SLO_IO jif=jiffies;while(time_before_eq(jiffies, jif+i2c_table[minor].veryslow))\ +- if (need_resched) schedule(); +-*/ +- + + /* ----- global variables --------------------------------------------- */ + +-#ifdef SLO_IO +- int jif; +-#endif +- + /* module parameters: + */ + static int i2c_debug; + static int bit_test; /* see if the line-setting functions work */ +-static int bit_scan; /* have a look at what's hanging 'round */ + + /* --- setting states on the bus with the right timing: --------------- */ + +@@ -88,9 +72,6 @@ + { + setscl(adap,0); + udelay(adap->udelay); +-#ifdef SLO_IO +- SLO_IO +-#endif + } + + /* +@@ -99,33 +80,35 @@ + */ + static inline int sclhi(struct i2c_algo_bit_data *adap) + { +- int start=jiffies; ++ int start; + + setscl(adap,1); + +- udelay(adap->udelay); +- + /* Not all adapters have scl sense line... */ +- if (adap->getscl == NULL ) ++ if (adap->getscl == NULL ) { ++ udelay(adap->udelay); + return 0; ++ } + +- while (! getscl(adap) ) { ++ start=jiffies; ++ while (! getscl(adap) ) { + /* the hw knows how to read the clock line, + * so we wait until it actually gets high. + * This is safer as some chips may hold it low + * while they are processing data internally. + */ +- setscl(adap,1); + if (time_after_eq(jiffies, start+adap->timeout)) { + return -ETIMEDOUT; + } ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) + if (current->need_resched) + schedule(); ++#else ++ cond_resched(); ++#endif + } + DEBSTAT(printk(KERN_DEBUG "needed %ld jiffies\n", jiffies-start)); +-#ifdef SLO_IO +- SLO_IO +-#endif ++ udelay(adap->udelay); + return 0; + } + +@@ -144,7 +127,7 @@ + /* scl, sda may not be high */ + DEBPROTO(printk(" Sr ")); + setsda(adap,1); +- setscl(adap,1); ++ sclhi(adap); + udelay(adap->udelay); + + sdalo(adap); +@@ -178,7 +161,6 @@ + struct i2c_algo_bit_data *adap = i2c_adap->algo_data; + + /* assert: scl is low */ +- DEB2(printk(KERN_DEBUG " i2c_outb:%2.2X\n",c&0xff)); + for ( i=7 ; i>=0 ; i-- ) { + sb = c & ( 1 << i ); + setsda(adap,sb); +@@ -186,6 +168,7 @@ + DEBPROTO(printk(KERN_DEBUG "%d",sb!=0)); + if (sclhi(adap)<0) { /* timed out */ + sdahi(adap); /* we don't want to block the net */ ++ DEB2(printk(KERN_DEBUG " i2c_outb: 0x%02x, timeout at bit #%d\n", c&0xff, i)); + return -ETIMEDOUT; + }; + /* do arbitration here: +@@ -196,11 +179,12 @@ + } + sdahi(adap); + if (sclhi(adap)<0){ /* timeout */ ++ DEB2(printk(KERN_DEBUG " i2c_outb: 0x%02x, timeout at ack\n", c&0xff)); + return -ETIMEDOUT; + }; + /* read ack: SDA should be pulled down by slave */ + ack=getsda(adap); /* ack: sda is pulled low ->success. */ +- DEB2(printk(KERN_DEBUG " i2c_outb: getsda() = 0x%2.2x\n", ~ack )); ++ DEB2(printk(KERN_DEBUG " i2c_outb: 0x%02x , getsda() = %d\n", c & 0xff, ack)); + + DEBPROTO( printk(KERN_DEBUG "[%2.2x]",c&0xff) ); + DEBPROTO(if (0==ack){ printk(KERN_DEBUG " A ");} else printk(KERN_DEBUG " NA ") ); +@@ -219,11 +203,10 @@ + struct i2c_algo_bit_data *adap = i2c_adap->algo_data; + + /* assert: scl is low */ +- DEB2(printk(KERN_DEBUG "i2c_inb.\n")); +- + sdahi(adap); + for (i=0;i<8;i++) { + if (sclhi(adap)<0) { /* timeout */ ++ DEB2(printk(KERN_DEBUG " i2c_inb: timeout at bit #%d\n", 7-i)); + return -ETIMEDOUT; + }; + indata *= 2; +@@ -232,6 +215,8 @@ + scllo(adap); + } + /* assert: scl is low */ ++ DEB2(printk(KERN_DEBUG "i2c_inb: 0x%02x\n", indata & 0xff)); ++ + DEBPROTO(printk(KERN_DEBUG " 0x%02x", indata & 0xff)); + return (int) (indata & 0xff); + } +@@ -242,71 +227,75 @@ + */ + static int test_bus(struct i2c_algo_bit_data *adap, char* name) { + int scl,sda; ++ ++ if (adap->getscl==NULL) ++ printk(KERN_INFO "i2c-algo-bit.o: Testing SDA only, " ++ "SCL is not readable.\n"); ++ + sda=getsda(adap); +- if (adap->getscl==NULL) { +- printk("i2c-algo-bit.o: Warning: Adapter can't read from clock line - skipping test.\n"); +- return 0; +- } +- scl=getscl(adap); +- printk("i2c-algo-bit.o: Adapter: %s scl: %d sda: %d -- testing...\n", +- name,getscl(adap),getsda(adap)); ++ scl=(adap->getscl==NULL?1:getscl(adap)); ++ printk(KERN_DEBUG "i2c-algo-bit.o: (0) scl=%d, sda=%d\n",scl,sda); + if (!scl || !sda ) { +- printk("i2c-algo-bit.o: %s seems to be busy.\n",name); ++ printk(KERN_WARNING "i2c-algo-bit.o: %s seems to be busy.\n", name); + goto bailout; + } ++ + sdalo(adap); +- printk("i2c-algo-bit.o:1 scl: %d sda: %d \n",getscl(adap), +- getsda(adap)); +- if ( 0 != getsda(adap) ) { +- printk("i2c-algo-bit.o: %s SDA stuck high!\n",name); +- sdahi(adap); ++ sda=getsda(adap); ++ scl=(adap->getscl==NULL?1:getscl(adap)); ++ printk(KERN_DEBUG "i2c-algo-bit.o: (1) scl=%d, sda=%d\n",scl,sda); ++ if ( 0 != sda ) { ++ printk(KERN_WARNING "i2c-algo-bit.o: SDA stuck high!\n"); + goto bailout; + } +- if ( 0 == getscl(adap) ) { +- printk("i2c-algo-bit.o: %s SCL unexpected low while pulling SDA low!\n", +- name); ++ if ( 0 == scl ) { ++ printk(KERN_WARNING "i2c-algo-bit.o: SCL unexpected low " ++ "while pulling SDA low!\n"); + goto bailout; + } ++ + sdahi(adap); +- printk("i2c-algo-bit.o:2 scl: %d sda: %d \n",getscl(adap), +- getsda(adap)); +- if ( 0 == getsda(adap) ) { +- printk("i2c-algo-bit.o: %s SDA stuck low!\n",name); +- sdahi(adap); ++ sda=getsda(adap); ++ scl=(adap->getscl==NULL?1:getscl(adap)); ++ printk(KERN_DEBUG "i2c-algo-bit.o: (2) scl=%d, sda=%d\n",scl,sda); ++ if ( 0 == sda ) { ++ printk(KERN_WARNING "i2c-algo-bit.o: SDA stuck low!\n"); + goto bailout; + } +- if ( 0 == getscl(adap) ) { +- printk("i2c-algo-bit.o: %s SCL unexpected low while SDA high!\n", +- name); +- goto bailout; ++ if ( 0 == scl ) { ++ printk(KERN_WARNING "i2c-algo-bit.o: SCL unexpected low " ++ "while pulling SDA high!\n"); ++ goto bailout; + } ++ + scllo(adap); +- printk("i2c-algo-bit.o:3 scl: %d sda: %d \n",getscl(adap), +- getsda(adap)); +- if ( 0 != getscl(adap) ) { +- printk("i2c-algo-bit.o: %s SCL stuck high!\n",name); +- sclhi(adap); ++ sda=getsda(adap); ++ scl=(adap->getscl==NULL?0:getscl(adap)); ++ printk(KERN_DEBUG "i2c-algo-bit.o: (3) scl=%d, sda=%d\n",scl,sda); ++ if ( 0 != scl ) { ++ printk(KERN_WARNING "i2c-algo-bit.o: SCL stuck high!\n"); + goto bailout; + } +- if ( 0 == getsda(adap) ) { +- printk("i2c-algo-bit.o: %s SDA unexpected low while pulling SCL low!\n", +- name); ++ if ( 0 == sda ) { ++ printk(KERN_WARNING "i2c-algo-bit.o: SDA unexpected low " ++ "while pulling SCL low!\n"); + goto bailout; + } ++ + sclhi(adap); +- printk("i2c-algo-bit.o:4 scl: %d sda: %d \n",getscl(adap), +- getsda(adap)); +- if ( 0 == getscl(adap) ) { +- printk("i2c-algo-bit.o: %s SCL stuck low!\n",name); +- sclhi(adap); ++ sda=getsda(adap); ++ scl=(adap->getscl==NULL?1:getscl(adap)); ++ printk(KERN_DEBUG "i2c-algo-bit.o: (4) scl=%d, sda=%d\n",scl,sda); ++ if ( 0 == scl ) { ++ printk(KERN_WARNING "i2c-algo-bit.o: SCL stuck low!\n"); + goto bailout; + } +- if ( 0 == getsda(adap) ) { +- printk("i2c-algo-bit.o: %s SDA unexpected low while SCL high!\n", +- name); ++ if ( 0 == sda ) { ++ printk(KERN_WARNING "i2c-algo-bit.o: SDA unexpected low " ++ "while pulling SCL high!\n"); + goto bailout; + } +- printk("i2c-algo-bit.o: %s passed test.\n",name); ++ printk(KERN_INFO "i2c-algo-bit.o: %s passed test.\n",name); + return 0; + bailout: + sdahi(adap); +@@ -340,16 +329,21 @@ + i2c_start(adap); + udelay(adap->udelay); + } +- DEB2(if (i) printk(KERN_DEBUG "i2c-algo-bit.o: needed %d retries for %d\n", +- i,addr)); ++ DEB2(if (i) ++ printk(KERN_DEBUG "i2c-algo-bit.o: Used %d tries to %s client at 0x%02x : %s\n", ++ i+1, addr & 1 ? "read" : "write", addr>>1, ++ ret==1 ? "success" : ret==0 ? "no ack" : "failed, timeout?" ) ++ ); + return ret; + } + +-static int sendbytes(struct i2c_adapter *i2c_adap,const char *buf, int count) ++static int sendbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg) + { + struct i2c_algo_bit_data *adap = i2c_adap->algo_data; + char c; +- const char *temp = buf; ++ const char *temp = msg->buf; ++ int count = msg->len; ++ unsigned short nak_ok = msg->flags & I2C_M_IGNORE_NAK; + int retval; + int wrcount=0; + +@@ -358,7 +352,7 @@ + DEB2(printk(KERN_DEBUG "i2c-algo-bit.o: %s sendbytes: writing %2.2X\n", + i2c_adap->name, c&0xff)); + retval = i2c_outb(i2c_adap,c); +- if (retval>0) { ++ if ((retval>0) || (nak_ok && (retval==0))) { /* ok or ignored NAK */ + count--; + temp++; + wrcount++; +@@ -377,12 +371,18 @@ + return wrcount; + } + +-static inline int readbytes(struct i2c_adapter *i2c_adap,char *buf,int count) ++static inline int readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg) + { +- char *temp = buf; + int inval; + int rdcount=0; /* counts bytes read */ + struct i2c_algo_bit_data *adap = i2c_adap->algo_data; ++ char *temp = msg->buf; ++ int count = msg->len; ++ int recv_len = 0; ++ ++ /* Receive [Count] for I2C_SMBUS_BLOCK_DATA or I2C_SMBUS_BLOCK_PROC_CALL protocol */ ++ if (msg->flags & I2C_M_RECV_LEN) ++ recv_len = 1; + + while (count > 0) { + inval = i2c_inb(i2c_adap); +@@ -395,6 +395,20 @@ + break; + } + ++ if (recv_len) { ++ recv_len = 0; ++ /* [Count] should be between 1 and 31 (I2C_SMBUS_BLOCK_MAX - 1). */ ++ if (inval > 0 && inval < I2C_SMBUS_BLOCK_MAX) { ++ count = inval + 1; /* plus one for [Count] itself */ ++ msg->len = count; ++ if (msg->flags & I2C_M_RECV_PEC) ++ count++; /* plus one for PEC */ ++ } else { ++ printk(KERN_ERR "i2c-algo-bit.o: readbytes: bad block count (%d).\n", inval); ++ break; ++ } ++ } ++ + if ( count > 1 ) { /* send ack */ + sdalo(adap); + DEBPROTO(printk(" Am ")); +@@ -419,31 +433,34 @@ + * try_address) and transmits the address in the necessary format to handle + * reads, writes as well as 10bit-addresses. + * returns: +- * 0 everything went okay, the chip ack'ed ++ * 0 everything went okay, the chip ack'ed, or IGNORE_NAK flag was set + * -x an error occurred (like: -EREMOTEIO if the device did not answer, or + * -ETIMEDOUT, for example if the lines are stuck...) + */ +-static inline int bit_doAddress(struct i2c_adapter *i2c_adap, +- struct i2c_msg *msg, int retries) ++static inline int bit_doAddress(struct i2c_adapter *i2c_adap, struct i2c_msg *msg) + { + unsigned short flags = msg->flags; ++ unsigned short nak_ok = msg->flags & I2C_M_IGNORE_NAK; + struct i2c_algo_bit_data *adap = i2c_adap->algo_data; + + unsigned char addr; +- int ret; ++ int ret, retries; ++ ++ retries = nak_ok ? 0 : i2c_adap->retries; ++ + if ( (flags & I2C_M_TEN) ) { + /* a ten bit address */ + addr = 0xf0 | (( msg->addr >> 7) & 0x03); + DEB2(printk(KERN_DEBUG "addr0: %d\n",addr)); + /* try extended address code...*/ + ret = try_address(i2c_adap, addr, retries); +- if (ret!=1) { ++ if ((ret != 1) && !nak_ok) { + printk(KERN_ERR "died at extended address code.\n"); + return -EREMOTEIO; + } + /* the remaining 8 bit address */ + ret = i2c_outb(i2c_adap,msg->addr & 0x7f); +- if (ret != 1) { ++ if ((ret != 1) && !nak_ok) { + /* the chip did not ack / xmission error occurred */ + printk(KERN_ERR "died at 2nd address code.\n"); + return -EREMOTEIO; +@@ -453,7 +470,7 @@ + /* okay, now switch into reading mode */ + addr |= 0x01; + ret = try_address(i2c_adap, addr, retries); +- if (ret!=1) { ++ if ((ret!=1) && !nak_ok) { + printk(KERN_ERR "died at extended address code.\n"); + return -EREMOTEIO; + } +@@ -465,10 +482,10 @@ + if (flags & I2C_M_REV_DIR_ADDR ) + addr ^= 1; + ret = try_address(i2c_adap, addr, retries); +- if (ret!=1) { ++ if ((ret!=1) && !nak_ok) + return -EREMOTEIO; +- } + } ++ + return 0; + } + +@@ -479,16 +496,18 @@ + struct i2c_algo_bit_data *adap = i2c_adap->algo_data; + + int i,ret; ++ unsigned short nak_ok; + + i2c_start(adap); + for (i=0;i<num;i++) { + pmsg = &msgs[i]; ++ nak_ok = pmsg->flags & I2C_M_IGNORE_NAK; + if (!(pmsg->flags & I2C_M_NOSTART)) { + if (i) { + i2c_repstart(adap); + } +- ret = bit_doAddress(i2c_adap,pmsg,i2c_adap->retries); +- if (ret != 0) { ++ ret = bit_doAddress(i2c_adap, pmsg); ++ if ((ret != 0) && !nak_ok) { + DEB2(printk(KERN_DEBUG "i2c-algo-bit.o: NAK from device addr %2.2x msg #%d\n", + msgs[i].addr,i)); + return (ret<0) ? ret : -EREMOTEIO; +@@ -496,14 +515,14 @@ + } + if (pmsg->flags & I2C_M_RD ) { + /* read bytes into buffer*/ +- ret = readbytes(i2c_adap,pmsg->buf,pmsg->len); ++ ret = readbytes(i2c_adap, pmsg); + DEB2(printk(KERN_DEBUG "i2c-algo-bit.o: read %d bytes.\n",ret)); + if (ret < pmsg->len ) { + return (ret<0)? ret : -EREMOTEIO; + } + } else { + /* write bytes from buffer */ +- ret = sendbytes(i2c_adap,pmsg->buf,pmsg->len); ++ ret = sendbytes(i2c_adap, pmsg); + DEB2(printk(KERN_DEBUG "i2c-algo-bit.o: wrote %d bytes.\n",ret)); + if (ret < pmsg->len ) { + return (ret<0) ? ret : -EREMOTEIO; +@@ -514,30 +533,25 @@ + return num; + } + +-static int algo_control(struct i2c_adapter *adapter, +- unsigned int cmd, unsigned long arg) +-{ +- return 0; +-} +- +-static u32 bit_func(struct i2c_adapter *adap) ++static u32 bit_func(struct i2c_adapter *i2c_adap) + { + return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR | +- I2C_FUNC_PROTOCOL_MANGLING; ++ I2C_FUNC_PROTOCOL_MANGLING | ++ I2C_FUNC_SMBUS_BLOCK_PROC_CALL | ++ I2C_FUNC_SMBUS_READ_BLOCK_DATA | ++ I2C_FUNC_SMBUS_BLOCK_PROC_CALL_PEC | ++ I2C_FUNC_SMBUS_READ_BLOCK_DATA_PEC; + } + + + /* -----exported algorithm data: ------------------------------------- */ + + static struct i2c_algorithm i2c_bit_algo = { +- "Bit-shift algorithm", +- I2C_ALGO_BIT, +- bit_xfer, +- NULL, +- NULL, /* slave_xmit */ +- NULL, /* slave_recv */ +- algo_control, /* ioctl */ +- bit_func, /* functionality */ ++ .owner = THIS_MODULE, ++ .name = "Bit-shift algorithm", ++ .id = I2C_ALGO_BIT, ++ .master_xfer = bit_xfer, ++ .functionality = bit_func, + }; + + /* +@@ -545,7 +559,6 @@ + */ + int i2c_bit_add_bus(struct i2c_adapter *adap) + { +- int i; + struct i2c_algo_bit_data *bit_adap = adap->algo_data; + + if (bit_test) { +@@ -565,78 +578,26 @@ + adap->timeout = 100; /* default values, should */ + adap->retries = 3; /* be replaced by defines */ + +- /* scan bus */ +- if (bit_scan) { +- int ack; +- printk(KERN_INFO " i2c-algo-bit.o: scanning bus %s.\n", +- adap->name); +- for (i = 0x00; i < 0xff; i+=2) { +- i2c_start(bit_adap); +- ack = i2c_outb(adap,i); +- i2c_stop(bit_adap); +- if (ack>0) { +- printk("(%02x)",i>>1); +- } else +- printk("."); +- } +- printk("\n"); +- } +- +-#ifdef MODULE +- MOD_INC_USE_COUNT; +-#endif + i2c_add_adapter(adap); +- + return 0; + } + + + int i2c_bit_del_bus(struct i2c_adapter *adap) + { +- int res; +- +- if ((res = i2c_del_adapter(adap)) < 0) +- return res; +- +- DEB2(printk("i2c-algo-bit.o: adapter unregistered: %s\n",adap->name)); +- +-#ifdef MODULE +- MOD_DEC_USE_COUNT; +-#endif +- return 0; +-} +- +-int __init i2c_algo_bit_init (void) +-{ +- printk(KERN_INFO "i2c-algo-bit.o: i2c bit algorithm module\n"); +- return 0; ++ return i2c_del_adapter(adap); + } + +- +- + EXPORT_SYMBOL(i2c_bit_add_bus); + EXPORT_SYMBOL(i2c_bit_del_bus); + +-#ifdef MODULE + MODULE_AUTHOR("Simon G. Vogl <simon@tk.uni-linz.ac.at>"); + MODULE_DESCRIPTION("I2C-Bus bit-banging algorithm"); + MODULE_LICENSE("GPL"); + + MODULE_PARM(bit_test, "i"); +-MODULE_PARM(bit_scan, "i"); + MODULE_PARM(i2c_debug,"i"); + + MODULE_PARM_DESC(bit_test, "Test the lines of the bus to see if it is stuck"); +-MODULE_PARM_DESC(bit_scan, "Scan for active chips on the bus"); + MODULE_PARM_DESC(i2c_debug, + "debug level - 0 off; 1 normal; 2,3 more verbose; 9 bit-protocol"); +- +-int init_module(void) +-{ +- return i2c_algo_bit_init(); +-} +- +-void cleanup_module(void) +-{ +-} +-#endif +--- linux-old/include/linux/i2c-algo-bit.h Sat Feb 5 06:47:38 2000 ++++ linux/include/linux/i2c-algo-bit.h Mon Dec 13 19:26:28 2004 +@@ -21,12 +21,10 @@ + /* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even + Frodo Looijaard <frodol@dds.nl> */ + +-/* $Id: i2c-algo-bit.h,v 1.7 1999/12/21 23:45:58 frodo Exp $ */ ++/* $Id: i2c-algo-bit.h,v 1.11 2003/07/25 07:56:42 khali Exp $ */ + +-#ifndef I2C_ALGO_BIT_H +-#define I2C_ALGO_BIT_H 1 +- +-#include <linux/i2c.h> ++#ifndef _LINUX_I2C_ALGO_BIT_H ++#define _LINUX_I2C_ALGO_BIT_H + + /* --- Defines for bit-adapters --------------------------------------- */ + /* +@@ -42,9 +40,10 @@ + int (*getscl) (void *data); + + /* local settings */ +- int udelay; +- int mdelay; +- int timeout; ++ int udelay; /* half-clock-cycle time in microsecs */ ++ /* i.e. clock is (500 / udelay) KHz */ ++ int mdelay; /* in millisecs, unused */ ++ int timeout; /* in jiffies */ + }; + + #define I2C_BIT_ADAP_MAX 16 +@@ -52,4 +51,4 @@ + int i2c_bit_add_bus(struct i2c_adapter *); + int i2c_bit_del_bus(struct i2c_adapter *); + +-#endif /* I2C_ALGO_BIT_H */ ++#endif /* _LINUX_I2C_ALGO_BIT_H */ +--- linux-old/drivers/i2c/i2c-algo-ibm_ocp.c Thu Jan 1 00:00:00 1970 ++++ linux/drivers/i2c/i2c-algo-ibm_ocp.c Mon Dec 13 19:26:29 2004 +@@ -0,0 +1,901 @@ ++/* ++ ------------------------------------------------------------------------- ++ i2c-algo-ibm_ocp.c i2c driver algorithms for IBM PPC 405 adapters ++ ------------------------------------------------------------------------- ++ ++ Ian DaSilva, MontaVista Software, Inc. ++ idasilva@mvista.com or source@mvista.com ++ ++ Copyright 2000 MontaVista Software Inc. ++ ++ Changes made to support the IIC peripheral on the IBM PPC 405 ++ ++ ++ --------------------------------------------------------------------------- ++ This file was highly leveraged from 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 ++ ++ With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and ++ Frodo Looijaard <frodol@dds.nl> ,and also from Martin Bailey ++ <mbailey@littlefeet-inc.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. ++ --------------------------------------------------------------------------- ++ ++ History: 01/20/12 - Armin ++ akuster@mvista.com ++ ported up to 2.4.16+ ++ ++ Version 02/03/25 - Armin ++ converted to ocp format ++ removed commented out or #if 0 code ++ added Gérard Basler's fix to iic_combined_transaction() such that it ++ returns the number of successfully completed transfers . ++*/ ++ ++ ++#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 <linux/i2c-algo-ibm_ocp.h> ++#include <asm/ocp.h> ++ ++ ++/* ----- 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 /* print several statistical values*/ ++#define DEBPROTO(x) if (i2c_debug>=9) x; ++ /* debug the protocol by showing transferred bits */ ++#define DEF_TIMEOUT 5 ++ ++ ++/* ----- global variables --------------------------------------------- */ ++ ++ ++/* module parameters: ++ */ ++static int i2c_debug=0; ++ ++/* --- setting states on the bus with the right timing: --------------- */ ++ ++#define iic_outb(adap, reg, val) adap->setiic(adap->data, (int) &(reg), val) ++#define iic_inb(adap, reg) adap->getiic(adap->data, (int) &(reg)) ++ ++#define IICO_I2C_SDAHIGH 0x0780 ++#define IICO_I2C_SDALOW 0x0781 ++#define IICO_I2C_SCLHIGH 0x0782 ++#define IICO_I2C_SCLLOW 0x0783 ++#define IICO_I2C_LINEREAD 0x0784 ++ ++#define IIC_SINGLE_XFER 0 ++#define IIC_COMBINED_XFER 1 ++ ++#define IIC_ERR_LOST_ARB -2 ++#define IIC_ERR_INCOMPLETE_XFR -3 ++#define IIC_ERR_NACK -1 ++ ++/* --- other auxiliary functions -------------------------------------- */ ++ ++ ++// ++// Description: Puts this process to sleep for a period equal to timeout ++// ++static inline void iic_sleep(unsigned long timeout) ++{ ++ schedule_timeout( timeout * HZ); ++} ++ ++ ++// ++// Description: This performs the IBM PPC 405 IIC initialization sequence ++// as described in the PPC405GP data book. ++// ++static int iic_init (struct i2c_algo_iic_data *adap) ++{ ++ struct iic_regs *iic; ++ struct iic_ibm *adap_priv_data = adap->data; ++ unsigned short retval; ++ iic = (struct iic_regs *) adap_priv_data->iic_base; ++ ++ /* Clear master low master address */ ++ iic_outb(adap,iic->lmadr, 0); ++ ++ /* Clear high master address */ ++ iic_outb(adap,iic->hmadr, 0); ++ ++ /* Clear low slave address */ ++ iic_outb(adap,iic->lsadr, 0); ++ ++ /* Clear high slave address */ ++ iic_outb(adap,iic->hsadr, 0); ++ ++ /* Clear status */ ++ iic_outb(adap,iic->sts, 0x0a); ++ ++ /* Clear extended status */ ++ iic_outb(adap,iic->extsts, 0x8f); ++ ++ /* Set clock division */ ++ iic_outb(adap,iic->clkdiv, 0x04); ++ ++ retval = iic_inb(adap, iic->clkdiv); ++ DEB(printk("iic_init: CLKDIV register = %x\n", retval)); ++ ++ /* Enable interrupts on Requested Master Transfer Complete */ ++ iic_outb(adap,iic->intmsk, 0x01); ++ ++ /* Clear transfer count */ ++ iic_outb(adap,iic->xfrcnt, 0x0); ++ ++ /* Clear extended control and status */ ++ iic_outb(adap,iic->xtcntlss, 0xf0); ++ ++ /* Set mode control (flush master data buf, enable hold SCL, exit */ ++ /* unknown state. */ ++ iic_outb(adap,iic->mdcntl, 0x47); ++ ++ /* Clear control register */ ++ iic_outb(adap,iic->cntl, 0x0); ++ ++ DEB2(printk(KERN_DEBUG "iic_init: Initialized IIC on PPC 405\n")); ++ return 0; ++} ++ ++ ++// ++// Description: After we issue a transaction on the IIC bus, this function ++// is called. It puts this process to sleep until we get an interrupt from ++// from the controller telling us that the transaction we requested in complete. ++// ++static int wait_for_pin(struct i2c_algo_iic_data *adap, int *status) ++{ ++ ++ int timeout = DEF_TIMEOUT; ++ int retval; ++ struct iic_regs *iic; ++ struct iic_ibm *adap_priv_data = adap->data; ++ iic = (struct iic_regs *) adap_priv_data->iic_base; ++ ++ ++ *status = iic_inb(adap, iic->sts); ++#ifndef STUB_I2C ++ ++ while (timeout-- && (*status & 0x01)) { ++ adap->waitforpin(adap->data); ++ *status = iic_inb(adap, iic->sts); ++ } ++#endif ++ if (timeout <= 0) { ++ /* Issue stop signal on the bus, and force an interrupt */ ++ retval = iic_inb(adap, iic->cntl); ++ iic_outb(adap, iic->cntl, retval | 0x80); ++ /* Clear status register */ ++ iic_outb(adap, iic->sts, 0x0a); ++ /* Exit unknown bus state */ ++ retval = iic_inb(adap, iic->mdcntl); ++ iic_outb(adap, iic->mdcntl, (retval | 0x02)); ++ ++ // Check the status of the controller. Does it still see a ++ // pending transfer, even though we've tried to stop any ++ // ongoing transaction? ++ retval = iic_inb(adap, iic->sts); ++ retval = retval & 0x01; ++ if(retval) { ++ // The iic controller is hosed. It is not responding to any ++ // of our commands. We have already tried to force it into ++ // a known state, but it has not worked. Our only choice now ++ // is a soft reset, which will clear all registers, and force ++ // us to re-initialize the controller. ++ /* Soft reset */ ++ iic_outb(adap, iic->xtcntlss, 0x01); ++ udelay(500); ++ iic_init(adap); ++ /* Is the pending transfer bit in the sts reg finally cleared? */ ++ retval = iic_inb(adap, iic->sts); ++ retval = retval & 0x01; ++ if(retval) { ++ printk(KERN_CRIT "The IIC Controller is hosed. A processor reset is required\n"); ++ } ++ // For some reason, even though the interrupt bit in this ++ // register was set during iic_init, it didn't take. We ++ // need to set it again. Don't ask me why....this is just what ++ // I saw when testing timeouts. ++ iic_outb(adap, iic->intmsk, 0x01); ++ } ++ return(-1); ++ } ++ else ++ return(0); ++} ++ ++ ++//------------------------------------ ++// Utility functions ++// ++ ++ ++// ++// Description: Look at the status register to see if there was an error ++// in the requested transaction. If there is, look at the extended status ++// register and determine the exact cause. ++// ++int analyze_status(struct i2c_algo_iic_data *adap, int *error_code) ++{ ++ int ret; ++ struct iic_regs *iic; ++ struct iic_ibm *adap_priv_data = adap->data; ++ iic = (struct iic_regs *) adap_priv_data->iic_base; ++ ++ ++ ret = iic_inb(adap, iic->sts); ++ if(ret & 0x04) { ++ // Error occurred ++ ret = iic_inb(adap, iic->extsts); ++ if(ret & 0x04) { ++ // Lost arbitration ++ *error_code = IIC_ERR_LOST_ARB; ++ } ++ if(ret & 0x02) { ++ // Incomplete transfer ++ *error_code = IIC_ERR_INCOMPLETE_XFR; ++ } ++ if(ret & 0x01) { ++ // Master transfer aborted by a NACK during the transfer of the ++ // address byte ++ *error_code = IIC_ERR_NACK; ++ } ++ return -1; ++ } ++ return 0; ++} ++ ++ ++// ++// Description: This function is called by the upper layers to do the ++// grunt work for a master send transaction ++// ++static int iic_sendbytes(struct i2c_adapter *i2c_adap,const char *buf, ++ int count, int xfer_flag) ++{ ++ struct iic_regs *iic; ++ struct i2c_algo_iic_data *adap = i2c_adap->algo_data; ++ struct iic_ibm *adap_priv_data = adap->data; ++ int wrcount, status, timeout; ++ int loops, remainder, i, j; ++ int ret, error_code; ++ iic = (struct iic_regs *) adap_priv_data->iic_base; ++ ++ ++ if( count == 0 ) return 0; ++ wrcount = 0; ++ loops = count / 4; ++ remainder = count % 4; ++ ++ if((loops > 1) && (remainder == 0)) { ++ for(i=0; i<(loops-1); i++) { ++ // ++ // Write four bytes to master data buffer ++ // ++ for(j=0; j<4; j++) { ++ iic_outb(adap, iic->mdbuf, ++ buf[wrcount++]); ++ } ++ // ++ // Issue command to IICO device to begin transmission ++ // ++ iic_outb(adap, iic->cntl, 0x35); ++ // ++ // Wait for transmission to complete. When it does, ++ //loop to the top of the for statement and write the ++ // next four bytes. ++ // ++ timeout = wait_for_pin(adap, &status); ++ if(timeout < 0) { ++ // ++ // Error handling ++ // ++ //printk(KERN_ERR "Error: write timeout\n"); ++ return wrcount; ++ } ++ ret = analyze_status(adap, &error_code); ++ if(ret < 0) { ++ if(error_code == IIC_ERR_INCOMPLETE_XFR) { ++ // Return the number of bytes transferred ++ ret = iic_inb(adap, iic->xfrcnt); ++ ret = ret & 0x07; ++ return (wrcount-4+ret); ++ } ++ else return error_code; ++ } ++ } ++ } ++ else if((loops >= 1) && (remainder > 0)){ ++ //printk(KERN_DEBUG "iic_sendbytes: (loops >= 1)\n"); ++ for(i=0; i<loops; i++) { ++ // ++ // Write four bytes to master data buffer ++ // ++ for(j=0; j<4; j++) { ++ iic_outb(adap, iic->mdbuf, ++ buf[wrcount++]); ++ } ++ // ++ // Issue command to IICO device to begin transmission ++ // ++ iic_outb(adap, iic->cntl, 0x35); ++ // ++ // Wait for transmission to complete. When it does, ++ //loop to the top of the for statement and write the ++ // next four bytes. ++ // ++ timeout = wait_for_pin(adap, &status); ++ if(timeout < 0) { ++ // ++ // Error handling ++ // ++ //printk(KERN_ERR "Error: write timeout\n"); ++ return wrcount; ++ } ++ ret = analyze_status(adap, &error_code); ++ if(ret < 0) { ++ if(error_code == IIC_ERR_INCOMPLETE_XFR) { ++ // Return the number of bytes transferred ++ ret = iic_inb(adap, iic->xfrcnt); ++ ret = ret & 0x07; ++ return (wrcount-4+ret); ++ } ++ else return error_code; ++ } ++ } ++ } ++ ++ //printk(KERN_DEBUG "iic_sendbytes: expedite write\n"); ++ if(remainder == 0) remainder = 4; ++ // remainder = remainder - 1; ++ // ++ // Write the remaining bytes (less than or equal to 4) ++ // ++ for(i=0; i<remainder; i++) { ++ iic_outb(adap, iic->mdbuf, buf[wrcount++]); ++ //printk(KERN_DEBUG "iic_sendbytes: data transferred = %x, wrcount = %d\n", buf[wrcount-1], (wrcount-1)); ++ } ++ //printk(KERN_DEBUG "iic_sendbytes: Issuing write\n"); ++ ++ if(xfer_flag == IIC_COMBINED_XFER) { ++ iic_outb(adap, iic->cntl, (0x09 | ((remainder-1) << 4))); ++ } ++ else { ++ iic_outb(adap, iic->cntl, (0x01 | ((remainder-1) << 4))); ++ } ++ DEB2(printk(KERN_DEBUG "iic_sendbytes: Waiting for interrupt\n")); ++ timeout = wait_for_pin(adap, &status); ++ if(timeout < 0) { ++ // ++ // Error handling ++ // ++ //printk(KERN_ERR "Error: write timeout\n"); ++ return wrcount; ++ } ++ ret = analyze_status(adap, &error_code); ++ if(ret < 0) { ++ if(error_code == IIC_ERR_INCOMPLETE_XFR) { ++ // Return the number of bytes transferred ++ ret = iic_inb(adap, iic->xfrcnt); ++ ret = ret & 0x07; ++ return (wrcount-4+ret); ++ } ++ else return error_code; ++ } ++ DEB2(printk(KERN_DEBUG "iic_sendbytes: Got interrupt\n")); ++ return wrcount; ++} ++ ++ ++// ++// Description: Called by the upper layers to do the grunt work for ++// a master read transaction. ++// ++static int iic_readbytes(struct i2c_adapter *i2c_adap, char *buf, int count, int xfer_type) ++{ ++ struct iic_regs *iic; ++ int rdcount=0, i, status, timeout; ++ struct i2c_algo_iic_data *adap = i2c_adap->algo_data; ++ struct iic_ibm *adap_priv_data = adap->data; ++ int loops, remainder, j; ++ int ret, error_code; ++ iic = (struct iic_regs *) adap_priv_data->iic_base; ++ ++ if(count == 0) return 0; ++ loops = count / 4; ++ remainder = count % 4; ++ ++ //printk(KERN_DEBUG "iic_readbytes: loops = %d, remainder = %d\n", loops, remainder); ++ ++ if((loops > 1) && (remainder == 0)) { ++ //printk(KERN_DEBUG "iic_readbytes: (loops > 1) && (remainder == 0)\n"); ++ for(i=0; i<(loops-1); i++) { ++ // ++ // Issue command to begin master read (4 bytes maximum) ++ // ++ //printk(KERN_DEBUG "--->Issued read command\n"); ++ iic_outb(adap, iic->cntl, 0x37); ++ // ++ // Wait for transmission to complete. When it does, ++ // loop to the top of the for statement and write the ++ // next four bytes. ++ // ++ //printk(KERN_DEBUG "--->Waiting for interrupt\n"); ++ timeout = wait_for_pin(adap, &status); ++ if(timeout < 0) { ++ // Error Handler ++ //printk(KERN_ERR "Error: read timed out\n"); ++ return rdcount; ++ } ++ //printk(KERN_DEBUG "--->Got interrupt\n"); ++ ++ ret = analyze_status(adap, &error_code); ++ if(ret < 0) { ++ if(error_code == IIC_ERR_INCOMPLETE_XFR) ++ return rdcount; ++ else ++ return error_code; ++ } ++ ++ for(j=0; j<4; j++) { ++ // Wait for data to shuffle to top of data buffer ++ // This value needs to optimized. ++ udelay(1); ++ buf[rdcount] = iic_inb(adap, iic->mdbuf); ++ rdcount++; ++ //printk(KERN_DEBUG "--->Read one byte\n"); ++ } ++ } ++ } ++ ++ else if((loops >= 1) && (remainder > 0)){ ++ //printk(KERN_DEBUG "iic_readbytes: (loops >=1) && (remainder > 0)\n"); ++ for(i=0; i<loops; i++) { ++ // ++ // Issue command to begin master read (4 bytes maximum) ++ // ++ //printk(KERN_DEBUG "--->Issued read command\n"); ++ iic_outb(adap, iic->cntl, 0x37); ++ // ++ // Wait for transmission to complete. When it does, ++ // loop to the top of the for statement and write the ++ // next four bytes. ++ // ++ //printk(KERN_DEBUG "--->Waiting for interrupt\n"); ++ timeout = wait_for_pin(adap, &status); ++ if(timeout < 0) { ++ // Error Handler ++ //printk(KERN_ERR "Error: read timed out\n"); ++ return rdcount; ++ } ++ //printk(KERN_DEBUG "--->Got interrupt\n"); ++ ++ ret = analyze_status(adap, &error_code); ++ if(ret < 0) { ++ if(error_code == IIC_ERR_INCOMPLETE_XFR) ++ return rdcount; ++ else ++ return error_code; ++ } ++ ++ for(j=0; j<4; j++) { ++ // Wait for data to shuffle to top of data buffer ++ // This value needs to optimized. ++ udelay(1); ++ buf[rdcount] = iic_inb(adap, iic->mdbuf); ++ rdcount++; ++ //printk(KERN_DEBUG "--->Read one byte\n"); ++ } ++ } ++ } ++ ++ //printk(KERN_DEBUG "iic_readbytes: expedite read\n"); ++ if(remainder == 0) remainder = 4; ++ DEB2(printk(KERN_DEBUG "iic_readbytes: writing %x to IICO_CNTL\n", (0x03 | ((remainder-1) << 4)))); ++ ++ if(xfer_type == IIC_COMBINED_XFER) { ++ iic_outb(adap, iic->cntl, (0x0b | ((remainder-1) << 4))); ++ } ++ else { ++ iic_outb(adap, iic->cntl, (0x03 | ((remainder-1) << 4))); ++ } ++ DEB2(printk(KERN_DEBUG "iic_readbytes: Wait for pin\n")); ++ timeout = wait_for_pin(adap, &status); ++ DEB2(printk(KERN_DEBUG "iic_readbytes: Got the interrupt\n")); ++ if(timeout < 0) { ++ // Error Handler ++ //printk(KERN_ERR "Error: read timed out\n"); ++ return rdcount; ++ } ++ ++ ret = analyze_status(adap, &error_code); ++ if(ret < 0) { ++ if(error_code == IIC_ERR_INCOMPLETE_XFR) ++ return rdcount; ++ else ++ return error_code; ++ } ++ ++ //printk(KERN_DEBUG "iic_readbyte: Begin reading data buffer\n"); ++ for(i=0; i<remainder; i++) { ++ buf[rdcount] = iic_inb(adap, iic->mdbuf); ++ // printk(KERN_DEBUG "iic_readbytes: Character read = %x\n", buf[rdcount]); ++ rdcount++; ++ } ++ ++ return rdcount; ++} ++ ++ ++// ++// Description: This function implements combined transactions. Combined ++// transactions consist of combinations of reading and writing blocks of data. ++// Each transfer (i.e. a read or a write) is separated by a repeated start ++// condition. ++// ++static int iic_combined_transaction(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num) ++{ ++ int i; ++ struct i2c_msg *pmsg; ++ int ret; ++ ++ DEB2(printk(KERN_DEBUG "Beginning combined transaction\n")); ++ for(i=0; i < num; i++) { ++ pmsg = &msgs[i]; ++ if(pmsg->flags & I2C_M_RD) { ++ ++ // Last read or write segment needs to be terminated with a stop ++ if(i < num-1) { ++ DEB2(printk(KERN_DEBUG "This one is a read\n")); ++ } ++ else { ++ DEB2(printk(KERN_DEBUG "Doing the last read\n")); ++ } ++ ret = iic_readbytes(i2c_adap, pmsg->buf, pmsg->len, (i < num-1) ? IIC_COMBINED_XFER : IIC_SINGLE_XFER); ++ ++ if (ret != pmsg->len) { ++ DEB2(printk("i2c-algo-ppc405.o: fail: " ++ "only read %d bytes.\n",ret)); ++ return i; ++ } ++ else { ++ DEB2(printk("i2c-algo-ppc405.o: read %d bytes.\n",ret)); ++ } ++ } ++ else if(!(pmsg->flags & I2C_M_RD)) { ++ ++ // Last read or write segment needs to be terminated with a stop ++ if(i < num-1) { ++ DEB2(printk(KERN_DEBUG "This one is a write\n")); ++ } ++ else { ++ DEB2(printk(KERN_DEBUG "Doing the last write\n")); ++ } ++ ret = iic_sendbytes(i2c_adap, pmsg->buf, pmsg->len, (i < num-1) ? IIC_COMBINED_XFER : IIC_SINGLE_XFER); ++ ++ if (ret != pmsg->len) { ++ DEB2(printk("i2c-algo-ppc405.o: fail: " ++ "only wrote %d bytes.\n",ret)); ++ return i; ++ } ++ else { ++ DEB2(printk("i2c-algo-ppc405.o: wrote %d bytes.\n",ret)); ++ } ++ } ++ } ++ ++ return num; ++} ++ ++ ++// ++// Description: Whenever we initiate a transaction, the first byte clocked ++// onto the bus after the start condition is the address (7 bit) of the ++// device we want to talk to. This function manipulates the address specified ++// so that it makes sense to the hardware when written to the IIC peripheral. ++// ++// Note: 10 bit addresses are not supported in this driver, although they are ++// supported by the hardware. This functionality needs to be implemented. ++// ++static inline int iic_doAddress(struct i2c_algo_iic_data *adap, ++ struct i2c_msg *msg, int retries) ++{ ++ struct iic_regs *iic; ++ unsigned short flags = msg->flags; ++ unsigned char addr; ++ struct iic_ibm *adap_priv_data = adap->data; ++ iic = (struct iic_regs *) adap_priv_data->iic_base; ++ ++// ++// The following segment for 10 bit addresses needs to be ported ++// ++/* Ten bit addresses not supported right now ++ if ( (flags & I2C_M_TEN) ) { ++ // a ten bit address ++ addr = 0xf0 | (( msg->addr >> 7) & 0x03); ++ DEB2(printk(KERN_DEBUG "addr0: %d\n",addr)); ++ // try extended address code... ++ ret = try_address(adap, addr, retries); ++ if (ret!=1) { ++ printk(KERN_ERR "iic_doAddress: died at extended address code.\n"); ++ return -EREMOTEIO; ++ } ++ // the remaining 8 bit address ++ iic_outb(adap,msg->addr & 0x7f); ++ // Status check comes here ++ if (ret != 1) { ++ printk(KERN_ERR "iic_doAddress: died at 2nd address code.\n"); ++ return -EREMOTEIO; ++ } ++ if ( flags & I2C_M_RD ) { ++ i2c_repstart(adap); ++ // okay, now switch into reading mode ++ addr |= 0x01; ++ ret = try_address(adap, addr, retries); ++ if (ret!=1) { ++ printk(KERN_ERR "iic_doAddress: died at extended address code.\n"); ++ return -EREMOTEIO; ++ } ++ } ++ } else ----------> // normal 7 bit address ++ ++Ten bit addresses not supported yet */ ++ ++ addr = ( msg->addr << 1 ); ++ if (flags & I2C_M_RD ) ++ addr |= 1; ++ if (flags & I2C_M_REV_DIR_ADDR ) ++ addr ^= 1; ++ // ++ // Write to the low slave address ++ // ++ iic_outb(adap, iic->lmadr, addr); ++ // ++ // Write zero to the high slave register since we are ++ // only using 7 bit addresses ++ // ++ iic_outb(adap, iic->hmadr, 0); ++ ++ return 0; ++} ++ ++ ++// ++// Description: Prepares the controller for a transaction (clearing status ++// registers, data buffers, etc), and then calls either iic_readbytes or ++// iic_sendbytes to do the actual transaction. ++// ++static int iic_xfer(struct i2c_adapter *i2c_adap, ++ struct i2c_msg msgs[], ++ int num) ++{ ++ struct iic_regs *iic; ++ struct i2c_algo_iic_data *adap = i2c_adap->algo_data; ++ struct iic_ibm *adap_priv_data = adap->data; ++ struct i2c_msg *pmsg; ++ int i = 0; ++ int ret; ++ iic = (struct iic_regs *) adap_priv_data->iic_base; ++ ++ pmsg = &msgs[i]; ++ ++ // ++ // Clear status register ++ // ++ DEB2(printk(KERN_DEBUG "iic_xfer: iic_xfer: Clearing status register\n")); ++ iic_outb(adap, iic->sts, 0x0a); ++ ++ // ++ // Wait for any pending transfers to complete ++ // ++ DEB2(printk(KERN_DEBUG "iic_xfer: Waiting for any pending transfers to complete\n")); ++ while((ret = iic_inb(adap, iic->sts)) == 0x01) { ++ ; ++ } ++ ++ // ++ // Flush master data buf ++ // ++ DEB2(printk(KERN_DEBUG "iic_xfer: Clearing master data buffer\n")); ++ ret = iic_inb(adap, iic->mdcntl); ++ iic_outb(adap, iic->mdcntl, ret | 0x40); ++ ++ // ++ // Load slave address ++ // ++ DEB2(printk(KERN_DEBUG "iic_xfer: Loading slave address\n")); ++ ret = iic_doAddress(adap, pmsg, i2c_adap->retries); ++ ++ // ++ // Check to see if the bus is busy ++ // ++ ret = iic_inb(adap, iic->extsts); ++ // Mask off the irrelevent bits ++ ret = ret & 0x70; ++ // When the bus is free, the BCS bits in the EXTSTS register are 0b100 ++ if(ret != 0x40) return IIC_ERR_LOST_ARB; ++ ++ // ++ // Combined transaction (read and write) ++ // ++ if(num > 1) { ++ DEB2(printk(KERN_DEBUG "iic_xfer: Call combined transaction\n")); ++ ret = iic_combined_transaction(i2c_adap, msgs, num); ++ } ++ // ++ // Read only ++ // ++ else if((num == 1) && (pmsg->flags & I2C_M_RD)) { ++ // ++ // Tell device to begin reading data from the master data ++ // ++ DEB2(printk(KERN_DEBUG "iic_xfer: Call adapter's read\n")); ++ ret = iic_readbytes(i2c_adap, pmsg->buf, pmsg->len, IIC_SINGLE_XFER); ++ } ++ // ++ // Write only ++ // ++ else if((num == 1 ) && (!(pmsg->flags & I2C_M_RD))) { ++ // ++ // Write data to master data buffers and tell our device ++ // to begin transmitting ++ // ++ DEB2(printk(KERN_DEBUG "iic_xfer: Call adapter's write\n")); ++ ret = iic_sendbytes(i2c_adap, pmsg->buf, pmsg->len, IIC_SINGLE_XFER); ++ } ++ ++ return ret; ++} ++ ++ ++// ++// Description: Implements device specific ioctls. Higher level ioctls can ++// be found in i2c-core.c and are typical of any i2c controller (specifying ++// slave address, timeouts, etc). These ioctls take advantage of any hardware ++// features built into the controller for which this algorithm-adapter set ++// was written. These ioctls allow you to take control of the data and clock ++// lines on the IBM PPC 405 IIC controller and set the either high or low, ++// similar to a GPIO pin. ++// ++static int algo_control(struct i2c_adapter *adapter, ++ unsigned int cmd, unsigned long arg) ++{ ++ struct iic_regs *iic; ++ struct i2c_algo_iic_data *adap = adapter->algo_data; ++ struct iic_ibm *adap_priv_data = adap->data; ++ int ret=0; ++ int lines; ++ iic = (struct iic_regs *) adap_priv_data->iic_base; ++ ++ lines = iic_inb(adap, iic->directcntl); ++ ++ if (cmd == IICO_I2C_SDAHIGH) { ++ lines = lines & 0x01; ++ if( lines ) lines = 0x04; ++ else lines = 0; ++ iic_outb(adap, iic->directcntl,(0x08|lines)); ++ } ++ else if (cmd == IICO_I2C_SDALOW) { ++ lines = lines & 0x01; ++ if( lines ) lines = 0x04; ++ else lines = 0; ++ iic_outb(adap, iic->directcntl,(0x00|lines)); ++ } ++ else if (cmd == IICO_I2C_SCLHIGH) { ++ lines = lines & 0x02; ++ if( lines ) lines = 0x08; ++ else lines = 0; ++ iic_outb(adap, iic->directcntl,(0x04|lines)); ++ } ++ else if (cmd == IICO_I2C_SCLLOW) { ++ lines = lines & 0x02; ++ if( lines ) lines = 0x08; ++ else lines = 0; ++ iic_outb(adap, iic->directcntl,(0x00|lines)); ++ } ++ else if (cmd == IICO_I2C_LINEREAD) { ++ ret = lines; ++ } ++ return ret; ++} ++ ++ ++static u32 iic_func(struct i2c_adapter *adap) ++{ ++ return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR | ++ I2C_FUNC_PROTOCOL_MANGLING; ++} ++ ++ ++/* -----exported algorithm data: ------------------------------------- */ ++ ++static struct i2c_algorithm iic_algo = { ++ .owner = THIS_MODULE, ++ .name = "IBM on-chip IIC algorithm", ++ .id = I2C_ALGO_OCP, ++ .master_xfer = iic_xfer, ++ .algo_control = algo_control, ++ .functionality = iic_func, ++}; ++ ++/* ++ * registering functions to load algorithms at runtime ++ */ ++ ++ ++// ++// Description: Register bus structure ++// ++int i2c_ocp_add_bus(struct i2c_adapter *adap) ++{ ++ struct i2c_algo_iic_data *iic_adap = adap->algo_data; ++ ++ DEB2(printk(KERN_DEBUG "i2c-algo-iic.o: hw routines for %s registered.\n", ++ adap->name)); ++ ++ /* register new adapter to i2c module... */ ++ ++ adap->id |= iic_algo.id; ++ adap->algo = &iic_algo; ++ ++ adap->timeout = 100; /* default values, should */ ++ adap->retries = 3; /* be replaced by defines */ ++ ++ iic_init(iic_adap); ++ i2c_add_adapter(adap); ++ return 0; ++} ++ ++ ++// ++// Done ++// ++int i2c_ocp_del_bus(struct i2c_adapter *adap) ++{ ++ return i2c_del_adapter(adap); ++} ++ ++ ++EXPORT_SYMBOL(i2c_ocp_add_bus); ++EXPORT_SYMBOL(i2c_ocp_del_bus); ++ ++// ++// The MODULE_* macros resolve to nothing if MODULES is not defined ++// when this file is compiled. ++// ++MODULE_AUTHOR("MontaVista Software <www.mvista.com>"); ++MODULE_DESCRIPTION("PPC 405 iic algorithm"); ++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"); ++ +--- linux-old/include/linux/i2c-algo-ibm_ocp.h Thu Jan 1 00:00:00 1970 ++++ linux/include/linux/i2c-algo-ibm_ocp.h Mon Dec 13 19:26:29 2004 +@@ -0,0 +1,52 @@ ++/* ------------------------------------------------------------------------- */ ++/* i2c-algo-ibm_ocp.h i2c driver algorithms for IBM PPC 405 IIC adapters */ ++/* ------------------------------------------------------------------------- */ ++/* 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> */ ++ ++/* Modifications by MontaVista Software, August 2000 ++ Changes made to support the IIC peripheral on the IBM PPC 405 */ ++ ++#ifndef _LINUX_I2C_ALGO_IBM_OCP_H ++#define _LINUX_I2C_ALGO_IBM_OCP_H ++ ++struct i2c_algo_iic_data { ++ struct iic_regs *data; /* private data for lolevel routines */ ++ void (*setiic) (void *data, int ctl, int val); ++ int (*getiic) (void *data, int ctl); ++ int (*getown) (void *data); ++ int (*getclock) (void *data); ++ void (*waitforpin) (void *data); ++ ++ /* local settings */ ++ int udelay; ++ int mdelay; ++ int timeout; ++}; ++ ++ ++#define I2C_IIC_ADAP_MAX 16 ++ ++ ++int i2c_ocp_add_bus(struct i2c_adapter *); ++int i2c_ocp_del_bus(struct i2c_adapter *); ++ ++#endif /* _LINUX_I2C_ALGO_IBM_OCP_H */ +--- linux-old/drivers/i2c/i2c-algo-pcf.c Tue Jan 20 15:10:31 2004 ++++ linux/drivers/i2c/i2c-algo-pcf.c Mon Dec 13 19:26:29 2004 +@@ -32,14 +32,11 @@ + #include <linux/delay.h> + #include <linux/slab.h> + #include <linux/init.h> +-#include <asm/uaccess.h> +-#include <linux/ioport.h> + #include <linux/errno.h> + #include <linux/sched.h> +- + #include <linux/i2c.h> + #include <linux/i2c-algo-pcf.h> +-#include "i2c-pcf8584.h" ++ + + /* ----- global defines ----------------------------------------------- */ + #define DEB(x) if (i2c_debug>=1) x +@@ -52,7 +49,6 @@ + /* module parameters: + */ + static int i2c_debug=0; +-static int pcf_scan=0; /* have a look at what's hanging 'round */ + + /* --- setting states on the bus with the right timing: --------------- */ + +@@ -149,8 +145,7 @@ + set_pcf(adap, 1, I2C_PCF_PIN); + /* check to see S1 now used as R/W ctrl - + PCF8584 does that when ESO is zero */ +- /* PCF also resets PIN bit */ +- if ((temp = get_pcf(adap, 1)) != (0)) { ++ if (((temp = get_pcf(adap, 1)) & 0x7f) != (0)) { + DEB2(printk(KERN_ERR "i2c-algo-pcf.o: PCF detection failed -- can't select S0 (0x%02x).\n", temp)); + return -ENXIO; /* definetly not PCF8584 */ + } +@@ -166,7 +161,7 @@ + /* S1=0xA0, next byte in S2 */ + set_pcf(adap, 1, I2C_PCF_PIN | I2C_PCF_ES1); + /* check to see S2 now selected */ +- if ((temp = get_pcf(adap, 1)) != I2C_PCF_ES1) { ++ if (((temp = get_pcf(adap, 1)) & 0x7f) != I2C_PCF_ES1) { + DEB2(printk(KERN_ERR "i2c-algo-pcf.o: PCF detection failed -- can't select S2 (0x%02x).\n", temp)); + return -ENXIO; + } +@@ -427,12 +422,6 @@ + return (i); + } + +-static int algo_control(struct i2c_adapter *adapter, +- unsigned int cmd, unsigned long arg) +-{ +- return 0; +-} +- + static u32 pcf_func(struct i2c_adapter *adap) + { + return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR | +@@ -442,14 +431,11 @@ + /* -----exported algorithm data: ------------------------------------- */ + + static struct i2c_algorithm pcf_algo = { +- "PCF8584 algorithm", +- I2C_ALGO_PCF, +- pcf_xfer, +- NULL, +- NULL, /* slave_xmit */ +- NULL, /* slave_recv */ +- algo_control, /* ioctl */ +- pcf_func, /* functionality */ ++ .owner = THIS_MODULE, ++ .name = "PCF8584 algorithm", ++ .id = I2C_ALGO_PCF, ++ .master_xfer = pcf_xfer, ++ .functionality = pcf_func, + }; + + /* +@@ -457,7 +443,7 @@ + */ + int i2c_pcf_add_bus(struct i2c_adapter *adap) + { +- int i, status; ++ int i; + struct i2c_algo_pcf_data *pcf_adap = adap->algo_data; + + DEB2(printk(KERN_DEBUG "i2c-algo-pcf.o: hw routines for %s registered.\n", +@@ -475,81 +461,23 @@ + return i; + } + +-#ifdef MODULE +- MOD_INC_USE_COUNT; +-#endif +- + i2c_add_adapter(adap); +- +- /* scan bus */ +- if (pcf_scan) { +- printk(KERN_INFO " i2c-algo-pcf.o: scanning bus %s.\n", +- adap->name); +- for (i = 0x00; i < 0xff; i+=2) { +- if (wait_for_bb(pcf_adap)) { +- printk(KERN_INFO " i2c-algo-pcf.o: scanning bus %s - TIMEOUTed.\n", +- adap->name); +- break; +- } +- i2c_outb(pcf_adap, i); +- i2c_start(pcf_adap); +- if ((wait_for_pin(pcf_adap, &status) >= 0) && +- ((status & I2C_PCF_LRB) == 0)) { +- printk("(%02x)",i>>1); +- } else { +- printk("."); +- } +- i2c_stop(pcf_adap); +- udelay(pcf_adap->udelay); +- } +- printk("\n"); +- } + return 0; + } + + + int i2c_pcf_del_bus(struct i2c_adapter *adap) + { +- int res; +- if ((res = i2c_del_adapter(adap)) < 0) +- return res; +- DEB2(printk("i2c-algo-pcf.o: adapter unregistered: %s\n",adap->name)); +- +-#ifdef MODULE +- MOD_DEC_USE_COUNT; +-#endif +- return 0; +-} +- +-int __init i2c_algo_pcf_init (void) +-{ +- printk("i2c-algo-pcf.o: i2c pcf8584 algorithm module\n"); +- return 0; ++ return i2c_del_adapter(adap); + } + +- + EXPORT_SYMBOL(i2c_pcf_add_bus); + EXPORT_SYMBOL(i2c_pcf_del_bus); + +-#ifdef MODULE + MODULE_AUTHOR("Hans Berglund <hb@spacetec.no>"); + MODULE_DESCRIPTION("I2C-Bus PCF8584 algorithm"); + MODULE_LICENSE("GPL"); + +-MODULE_PARM(pcf_scan, "i"); + MODULE_PARM(i2c_debug,"i"); +- +-MODULE_PARM_DESC(pcf_scan, "Scan for active chips on the bus"); + MODULE_PARM_DESC(i2c_debug, + "debug level - 0 off; 1 normal; 2,3 more verbose; 9 pcf-protocol"); +- +- +-int init_module(void) +-{ +- return i2c_algo_pcf_init(); +-} +- +-void cleanup_module(void) +-{ +-} +-#endif +--- linux-old/include/linux/i2c-algo-pcf.h Thu Mar 23 02:26:01 2000 ++++ linux/include/linux/i2c-algo-pcf.h Mon Dec 13 19:26:30 2004 +@@ -22,13 +22,12 @@ + /* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even + Frodo Looijaard <frodol@dds.nl> */ + +-/* $Id: i2c-algo-pcf.h,v 1.7 2000/02/27 23:02:45 frodo Exp $ */ ++/* $Id: i2c-algo-pcf.h,v 1.9 2003/07/25 07:56:42 khali Exp $ */ + +-#ifndef I2C_ALGO_PCF_H +-#define I2C_ALGO_PCF_H 1 ++#ifndef _LINUX_I2C_ALGO_PCF_H ++#define _LINUX_I2C_ALGO_PCF_H + +-/* --- Defines for pcf-adapters --------------------------------------- */ +-#include <linux/i2c.h> ++#include <linux/i2c-pcf8584.h> + + struct i2c_algo_pcf_data { + void *data; /* private data for lolevel routines */ +@@ -49,4 +48,4 @@ + int i2c_pcf_add_bus(struct i2c_adapter *); + int i2c_pcf_del_bus(struct i2c_adapter *); + +-#endif /* I2C_ALGO_PCF_H */ ++#endif /* _LINUX_I2C_ALGO_PCF_H */ +--- linux-old/drivers/i2c/i2c-core.c Wed Jul 7 00:38:02 2004 ++++ linux/drivers/i2c/i2c-core.c Mon Dec 13 19:26:31 2004 +@@ -18,56 +18,33 @@ + /* ------------------------------------------------------------------------- */ + + /* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi>. +- All SMBus-related things are written by Frodo Looijaard <frodol@dds.nl> */ ++ All SMBus-related things are written by Frodo Looijaard <frodol@dds.nl> ++ SMBus 2.0 support by Mark Studebaker <mdsxyz123@yahoo.com> */ + +-/* $Id: i2c-core.c,v 1.64 2001/08/13 01:35:56 mds Exp $ */ ++/* i2c-core.c,v 1.91.2.2 2003/01/21 10:00:19 kmalkki Exp */ + + #include <linux/module.h> + #include <linux/kernel.h> + #include <linux/errno.h> + #include <linux/slab.h> + #include <linux/proc_fs.h> +-#include <linux/config.h> +- +-#include <linux/i2c.h> +- +-/* ----- compatibility stuff ----------------------------------------------- */ +- + #include <linux/init.h> +- ++#include <linux/i2c.h> + #include <asm/uaccess.h> + + /* ----- global defines ---------------------------------------------------- */ + +-/* exclusive access to the bus */ +-#define I2C_LOCK(adap) down(&adap->lock) +-#define I2C_UNLOCK(adap) up(&adap->lock) +- +-#define ADAP_LOCK() down(&adap_lock) +-#define ADAP_UNLOCK() up(&adap_lock) +- +-#define DRV_LOCK() down(&driver_lock) +-#define DRV_UNLOCK() up(&driver_lock) +- + #define DEB(x) if (i2c_debug>=1) x; + #define DEB2(x) if (i2c_debug>=2) x; + + /* ----- global variables -------------------------------------------------- */ + +-/**** lock for writing to global variables: the adapter & driver list */ +-struct semaphore adap_lock; +-struct semaphore driver_lock; +- +-/**** adapter list */ ++DECLARE_MUTEX(core_lists); + static struct i2c_adapter *adapters[I2C_ADAP_MAX]; +-static int adap_count; +- +-/**** drivers list */ + static struct i2c_driver *drivers[I2C_DRIVER_MAX]; +-static int driver_count; + + /**** debug level */ +-static int i2c_debug=1; ++static int i2c_debug; + + /* --------------------------------------------------- + * /proc entry declarations +@@ -75,10 +52,6 @@ + */ + + #ifdef CONFIG_PROC_FS +- +-static int i2cproc_init(void); +-static int i2cproc_cleanup(void); +- + static ssize_t i2cproc_bus_read(struct file * file, char * buf,size_t count, + loff_t *ppos); + static int read_bus_i2c(char *buf, char **start, off_t offset, int len, +@@ -87,15 +60,11 @@ + /* To implement the dynamic /proc/bus/i2c-? files, we need our own + implementation of the read hook */ + static struct file_operations i2cproc_operations = { +- read: i2cproc_bus_read, ++ .read = i2cproc_bus_read, + }; + +-static int i2cproc_initialized = 0; +- +-#else /* undef CONFIG_PROC_FS */ +- +-#define i2cproc_init() 0 +-#define i2cproc_cleanup() 0 ++static int i2cproc_register(struct i2c_adapter *adap, int bus); ++static void i2cproc_remove(int bus); + + #endif /* CONFIG_PROC_FS */ + +@@ -112,9 +81,9 @@ + */ + int i2c_add_adapter(struct i2c_adapter *adap) + { +- int i,j,res; ++ int i,j,res = 0; + +- ADAP_LOCK(); ++ down(&core_lists); + for (i = 0; i < I2C_ADAP_MAX; i++) + if (NULL == adapters[i]) + break; +@@ -125,68 +94,39 @@ + res = -ENOMEM; + goto ERROR0; + } ++ ++#ifdef CONFIG_PROC_FS ++ res = i2cproc_register(adap, i); ++ if (res<0) ++ goto ERROR0; ++#endif /* def CONFIG_PROC_FS */ + + adapters[i] = adap; +- adap_count++; +- ADAP_UNLOCK(); + + /* init data types */ +- init_MUTEX(&adap->lock); +- +-#ifdef CONFIG_PROC_FS +- +- if (i2cproc_initialized) { +- char name[8]; +- struct proc_dir_entry *proc_entry; +- +- sprintf(name,"i2c-%d", i); +- +- proc_entry = create_proc_entry(name,0,proc_bus); +- if (! proc_entry) { +- printk("i2c-core.o: Could not create /proc/bus/%s\n", +- name); +- res = -ENOENT; +- goto ERROR1; +- } +- +- proc_entry->proc_fops = &i2cproc_operations; +- proc_entry->owner = THIS_MODULE; +- adap->inode = proc_entry->low_ino; +- } +- +-#endif /* def CONFIG_PROC_FS */ ++ init_MUTEX(&adap->bus); ++ init_MUTEX(&adap->list); + + /* inform drivers of new adapters */ +- DRV_LOCK(); + for (j=0;j<I2C_DRIVER_MAX;j++) + if (drivers[j]!=NULL && + (drivers[j]->flags&(I2C_DF_NOTIFY|I2C_DF_DUMMY))) + /* We ignore the return code; if it fails, too bad */ + drivers[j]->attach_adapter(adap); +- DRV_UNLOCK(); + + DEB(printk(KERN_DEBUG "i2c-core.o: adapter %s registered as adapter %d.\n", + adap->name,i)); +- +- return 0; +- +- +-ERROR1: +- ADAP_LOCK(); +- adapters[i] = NULL; +- adap_count--; + ERROR0: +- ADAP_UNLOCK(); ++ up(&core_lists); + return res; + } + + + int i2c_del_adapter(struct i2c_adapter *adap) + { +- int i,j,res; +- +- ADAP_LOCK(); ++ int i,j,res = 0; + ++ down(&core_lists); + for (i = 0; i < I2C_ADAP_MAX; i++) + if (adap == adapters[i]) + break; +@@ -202,20 +142,17 @@ + * *detach* it! Of course, each dummy driver should know about + * this or hell will break loose... + */ +- DRV_LOCK(); + for (j = 0; j < I2C_DRIVER_MAX; j++) + if (drivers[j] && (drivers[j]->flags & I2C_DF_DUMMY)) + if ((res = drivers[j]->attach_adapter(adap))) { + printk(KERN_WARNING "i2c-core.o: can't detach adapter %s " + "while detaching driver %s: driver not " + "detached!",adap->name,drivers[j]->name); +- goto ERROR1; ++ goto ERROR0; + } +- DRV_UNLOCK(); +- + + /* detach any active clients. This must be done first, because +- * it can fail; in which case we give upp. */ ++ * it can fail; in which case we give up. */ + for (j=0;j<I2C_CLIENT_MAX;j++) { + struct i2c_client *client = adap->clients[j]; + if (client!=NULL) +@@ -231,26 +168,15 @@ + goto ERROR0; + } + } ++ + #ifdef CONFIG_PROC_FS +- if (i2cproc_initialized) { +- char name[8]; +- sprintf(name,"i2c-%d", i); +- remove_proc_entry(name,proc_bus); +- } ++ i2cproc_remove(i); + #endif /* def CONFIG_PROC_FS */ + + adapters[i] = NULL; +- adap_count--; +- +- ADAP_UNLOCK(); + DEB(printk(KERN_DEBUG "i2c-core.o: adapter unregistered: %s\n",adap->name)); +- return 0; +- + ERROR0: +- ADAP_UNLOCK(); +- return res; +-ERROR1: +- DRV_UNLOCK(); ++ up(&core_lists); + return res; + } + +@@ -264,7 +190,8 @@ + int i2c_add_driver(struct i2c_driver *driver) + { + int i; +- DRV_LOCK(); ++ ++ down(&core_lists); + for (i = 0; i < I2C_DRIVER_MAX; i++) + if (NULL == drivers[i]) + break; +@@ -273,19 +200,12 @@ + " i2c-core.o: register_driver(%s) " + "- enlarge I2C_DRIVER_MAX.\n", + driver->name); +- DRV_UNLOCK(); ++ up(&core_lists); + return -ENOMEM; + } +- + drivers[i] = driver; +- driver_count++; +- +- DRV_UNLOCK(); /* driver was successfully added */ +- + DEB(printk(KERN_DEBUG "i2c-core.o: driver %s registered.\n",driver->name)); + +- ADAP_LOCK(); +- + /* now look for instances of driver on our adapters + */ + if (driver->flags& (I2C_DF_NOTIFY|I2C_DF_DUMMY)) { +@@ -294,15 +214,15 @@ + /* Ignore errors */ + driver->attach_adapter(adapters[i]); + } +- ADAP_UNLOCK(); ++ up(&core_lists); + return 0; + } + + int i2c_del_driver(struct i2c_driver *driver) + { +- int i,j,k,res; ++ int i,j,k,res = 0; + +- DRV_LOCK(); ++ down(&core_lists); + for (i = 0; i < I2C_DRIVER_MAX; i++) + if (driver == drivers[i]) + break; +@@ -310,7 +230,7 @@ + printk(KERN_WARNING " i2c-core.o: unregister_driver: " + "[%s] not found\n", + driver->name); +- DRV_UNLOCK(); ++ up(&core_lists); + return -ENODEV; + } + /* Have a look at each adapter, if clients of this driver are still +@@ -322,7 +242,6 @@ + * invalid operation might (will!) result, when using stale client + * pointers. + */ +- ADAP_LOCK(); /* should be moved inside the if statement... */ + for (k=0;k<I2C_ADAP_MAX;k++) { + struct i2c_adapter *adap = adapters[k]; + if (adap == NULL) /* skip empty entries. */ +@@ -341,8 +260,7 @@ + "not be detached properly; driver " + "not unloaded!",driver->name, + adap->name); +- ADAP_UNLOCK(); +- return res; ++ goto ERROR0; + } + } else { + for (j=0;j<I2C_CLIENT_MAX;j++) { +@@ -359,37 +277,47 @@ + "unregistering driver " + "`%s', the client at " + "address %02x of " +- "adapter `%s' could not" +- "be detached; driver" ++ "adapter `%s' could not " ++ "be detached; driver " + "not unloaded!", + driver->name, + client->addr, + adap->name); +- ADAP_UNLOCK(); +- return res; ++ goto ERROR0; + } + } + } + } + } +- ADAP_UNLOCK(); + drivers[i] = NULL; +- driver_count--; +- DRV_UNLOCK(); +- + DEB(printk(KERN_DEBUG "i2c-core.o: driver unregistered: %s\n",driver->name)); +- return 0; ++ ++ERROR0: ++ up(&core_lists); ++ return res; + } + +-int i2c_check_addr (struct i2c_adapter *adapter, int addr) ++static int __i2c_check_addr (struct i2c_adapter *adapter, int addr) + { + int i; + for (i = 0; i < I2C_CLIENT_MAX ; i++) + if (adapter->clients[i] && (adapter->clients[i]->addr == addr)) + return -EBUSY; ++ + return 0; + } + ++int i2c_check_addr (struct i2c_adapter *adapter, int addr) ++{ ++ int rval; ++ ++ down(&adapter->list); ++ rval = __i2c_check_addr(adapter, addr); ++ up(&adapter->list); ++ ++ return rval; ++} ++ + int i2c_attach_client(struct i2c_client *client) + { + struct i2c_adapter *adapter = client->adapter; +@@ -398,6 +326,7 @@ + if (i2c_check_addr(client->adapter,client->addr)) + return -EBUSY; + ++ down(&adapter->list); + for (i = 0; i < I2C_CLIENT_MAX; i++) + if (NULL == adapter->clients[i]) + break; +@@ -405,11 +334,11 @@ + printk(KERN_WARNING + " i2c-core.o: attach_client(%s) - enlarge I2C_CLIENT_MAX.\n", + client->name); ++ up(&adapter->list); + return -ENOMEM; + } +- + adapter->clients[i] = client; +- adapter->client_count++; ++ up(&adapter->list); + + if (adapter->client_register) + if (adapter->client_register(client)) +@@ -431,16 +360,6 @@ + struct i2c_adapter *adapter = client->adapter; + int i,res; + +- for (i = 0; i < I2C_CLIENT_MAX; i++) +- if (client == adapter->clients[i]) +- break; +- if (I2C_CLIENT_MAX == i) { +- printk(KERN_WARNING " i2c-core.o: unregister_client " +- "[%s] not found\n", +- client->name); +- return -ENODEV; +- } +- + if( (client->flags & I2C_CLIENT_ALLOW_USE) && + (client->usage_count>0)) + return -EBUSY; +@@ -452,33 +371,41 @@ + return res; + } + ++ down(&adapter->list); ++ for (i = 0; i < I2C_CLIENT_MAX; i++) ++ if (client == adapter->clients[i]) ++ break; ++ if (I2C_CLIENT_MAX == i) { ++ printk(KERN_WARNING " i2c-core.o: unregister_client " ++ "[%s] not found\n", ++ client->name); ++ up(&adapter->list); ++ return -ENODEV; ++ } + adapter->clients[i] = NULL; +- adapter->client_count--; ++ up(&adapter->list); + + DEB(printk(KERN_DEBUG "i2c-core.o: client [%s] unregistered.\n",client->name)); + return 0; + } + +-void i2c_inc_use_client(struct i2c_client *client) ++static void i2c_inc_use_client(struct i2c_client *client) + { +- +- if (client->driver->inc_use != NULL) +- client->driver->inc_use(client); +- +- if (client->adapter->inc_use != NULL) +- client->adapter->inc_use(client->adapter); ++ if(client->driver->owner) ++ __MOD_INC_USE_COUNT(client->driver->owner); ++ if(client->adapter->owner) ++ __MOD_INC_USE_COUNT(client->adapter->owner); + } + +-void i2c_dec_use_client(struct i2c_client *client) ++static void i2c_dec_use_client(struct i2c_client *client) + { +- +- if (client->driver->dec_use != NULL) +- client->driver->dec_use(client); +- +- if (client->adapter->dec_use != NULL) +- client->adapter->dec_use(client->adapter); ++ if(client->driver->owner) ++ __MOD_DEC_USE_COUNT(client->driver->owner); ++ if(client->adapter->owner) ++ __MOD_DEC_USE_COUNT(client->adapter->owner); + } + ++#if 0 /* just forget about this for now --km */ + struct i2c_client *i2c_get_client(int driver_id, int adapter_id, + struct i2c_client *prev) + { +@@ -545,18 +472,17 @@ + + return 0; + } ++#endif + + int i2c_use_client(struct i2c_client *client) + { +- if(client->flags & I2C_CLIENT_ALLOW_USE) { +- if (client->flags & I2C_CLIENT_ALLOW_MULTIPLE_USE) ++ if (client->flags & I2C_CLIENT_ALLOW_USE) { ++ if (client->flags & I2C_CLIENT_ALLOW_MULTIPLE_USE) ++ client->usage_count++; ++ else if (client->usage_count > 0) ++ return -EBUSY; ++ else + client->usage_count++; +- else { +- if(client->usage_count > 0) +- return -EBUSY; +- else +- client->usage_count++; +- } + } + + i2c_inc_use_client(client); +@@ -589,12 +515,13 @@ + #ifdef CONFIG_PROC_FS + + /* This function generates the output for /proc/bus/i2c */ +-int read_bus_i2c(char *buf, char **start, off_t offset, int len, int *eof, ++static int read_bus_i2c(char *buf, char **start, off_t offset, int len, int *eof, + void *private) + { + int i; + int nr = 0; + /* Note that it is safe to write a `little' beyond len. Yes, really. */ ++ down(&core_lists); + for (i = 0; (i < I2C_ADAP_MAX) && (nr < len); i++) + if (adapters[i]) { + nr += sprintf(buf+nr, "i2c-%d\t", i); +@@ -611,6 +538,7 @@ + adapters[i]->name, + adapters[i]->algo->name); + } ++ up(&core_lists); + return nr; + } + +@@ -621,98 +549,125 @@ + struct inode * inode = file->f_dentry->d_inode; + char *kbuf; + struct i2c_client *client; ++ struct i2c_adapter *adap; + int i,j,k,order_nr,len=0; + size_t len_total; + int order[I2C_CLIENT_MAX]; ++#define OUTPUT_LENGTH_PER_LINE 70 + +- if (count > 4000) +- return -EINVAL; + len_total = file->f_pos + count; +- /* Too bad if this gets longer (unlikely) */ +- if (len_total > 4000) +- len_total = 4000; +- for (i = 0; i < I2C_ADAP_MAX; i++) +- if (adapters[i]->inode == inode->i_ino) { +- /* We need a bit of slack in the kernel buffer; this makes the +- sprintf safe. */ +- if (! (kbuf = kmalloc(count + 80,GFP_KERNEL))) +- return -ENOMEM; +- /* Order will hold the indexes of the clients +- sorted by address */ +- order_nr=0; +- for (j = 0; j < I2C_CLIENT_MAX; j++) { +- if ((client = adapters[i]->clients[j]) && +- (client->driver->id != I2C_DRIVERID_I2CDEV)) { +- for(k = order_nr; +- (k > 0) && +- adapters[i]->clients[order[k-1]]-> +- addr > client->addr; +- k--) +- order[k] = order[k-1]; +- order[k] = j; +- order_nr++; +- } +- } +- +- +- for (j = 0; (j < order_nr) && (len < len_total); j++) { +- client = adapters[i]->clients[order[j]]; +- len += sprintf(kbuf+len,"%02x\t%-32s\t%-32s\n", +- client->addr, +- client->name, +- client->driver->name); +- } +- len = len - file->f_pos; +- if (len > count) +- len = count; +- if (len < 0) +- len = 0; +- if (copy_to_user (buf,kbuf+file->f_pos, len)) { +- kfree(kbuf); +- return -EFAULT; +- } +- file->f_pos += len; +- kfree(kbuf); +- return len; +- } +- return -ENOENT; ++ if (len_total > (I2C_CLIENT_MAX * OUTPUT_LENGTH_PER_LINE) ) ++ /* adjust to maximum file size */ ++ len_total = (I2C_CLIENT_MAX * OUTPUT_LENGTH_PER_LINE); ++ ++ down(&core_lists); ++ /* adap = file->private_data; ?? --km */ ++ for (i = 0; i < I2C_ADAP_MAX; i++) { ++ adap = adapters[i]; ++ if (adap && (adap->inode == inode->i_ino)) ++ break; ++ } ++ if ( I2C_ADAP_MAX == i ) { ++ up(&core_lists); ++ return -ENOENT; ++ } ++ ++ /* We need a bit of slack in the kernel buffer; this makes the ++ sprintf safe. */ ++ if (! (kbuf = kmalloc(len_total + ++ OUTPUT_LENGTH_PER_LINE, ++ GFP_KERNEL))) ++ return -ENOMEM; ++ ++ /* Order will hold the indexes of the clients ++ sorted by address */ ++ order_nr=0; ++ down(&adap->list); ++ for (j = 0; j < I2C_CLIENT_MAX; j++) { ++ if ((client = adap->clients[j]) && ++ (client->driver->id != I2C_DRIVERID_I2CDEV)) { ++ for(k = order_nr; ++ (k > 0) && ++ adap->clients[order[k-1]]-> ++ addr > client->addr; ++ k--) ++ order[k] = order[k-1]; ++ order[k] = j; ++ order_nr++; ++ } ++ } ++ ++ ++ for (j = 0; (j < order_nr) && (len < len_total); j++) { ++ client = adap->clients[order[j]]; ++ len += sprintf(kbuf+len,"%02x\t%-32s\t%-32s\n", ++ client->addr, ++ client->name, ++ client->driver->name); ++ } ++ up(&adap->list); ++ up(&core_lists); ++ ++ len = len - file->f_pos; ++ if (len > count) ++ len = count; ++ if (len < 0) ++ len = 0; ++ if (copy_to_user (buf,kbuf+file->f_pos, len)) { ++ kfree(kbuf); ++ return -EFAULT; ++ } ++ file->f_pos += len; ++ kfree(kbuf); ++ return len; ++} ++ ++static int i2cproc_register(struct i2c_adapter *adap, int bus) ++{ ++ char name[8]; ++ struct proc_dir_entry *proc_entry; ++ ++ sprintf(name,"i2c-%d", bus); ++ proc_entry = create_proc_entry(name,0,proc_bus); ++ if (! proc_entry) { ++ printk(KERN_ERR "i2c-core.o: Could not create /proc/bus/%s\n", ++ name); ++ return -ENOENT; ++ } ++ ++ proc_entry->proc_fops = &i2cproc_operations; ++ proc_entry->owner = adap->owner; ++ adap->inode = proc_entry->low_ino; ++ return 0; + } + +-int i2cproc_init(void) ++static void i2cproc_remove(int bus) + { ++ char name[8]; ++ sprintf(name,"i2c-%d", bus); ++ remove_proc_entry(name, proc_bus); ++} + ++static int __init i2cproc_init(void) ++{ + struct proc_dir_entry *proc_bus_i2c; + +- i2cproc_initialized = 0; +- +- if (! proc_bus) { +- printk("i2c-core.o: /proc/bus/ does not exist"); +- i2cproc_cleanup(); +- return -ENOENT; +- } + proc_bus_i2c = create_proc_entry("i2c",0,proc_bus); + if (!proc_bus_i2c) { + printk(KERN_ERR "i2c-core.o: Could not create /proc/bus/i2c"); +- i2cproc_cleanup(); + return -ENOENT; + } ++ + proc_bus_i2c->read_proc = &read_bus_i2c; + proc_bus_i2c->owner = THIS_MODULE; +- i2cproc_initialized += 2; + return 0; + } + +-int i2cproc_cleanup(void) ++static void __exit i2cproc_cleanup(void) + { +- +- if (i2cproc_initialized >= 1) { +- remove_proc_entry("i2c",proc_bus); +- i2cproc_initialized -= 2; +- } +- return 0; ++ remove_proc_entry("i2c",proc_bus); + } + +- + #endif /* def CONFIG_PROC_FS */ + + /* ---------------------------------------------------- +@@ -728,9 +683,9 @@ + DEB2(printk(KERN_DEBUG "i2c-core.o: master_xfer: %s with %d msgs.\n", + adap->name,num)); + +- I2C_LOCK(adap); ++ down(&adap->bus); + ret = adap->algo->master_xfer(adap,msgs,num); +- I2C_UNLOCK(adap); ++ up(&adap->bus); + + return ret; + } else { +@@ -755,9 +710,9 @@ + DEB2(printk(KERN_DEBUG "i2c-core.o: master_send: writing %d bytes on %s.\n", + count,client->adapter->name)); + +- I2C_LOCK(adap); ++ down(&adap->bus); + ret = adap->algo->master_xfer(adap,&msg,1); +- I2C_UNLOCK(adap); ++ up(&adap->bus); + + /* if everything went ok (i.e. 1 msg transmitted), return #bytes + * transmitted, else error code. +@@ -785,9 +740,9 @@ + DEB2(printk(KERN_DEBUG "i2c-core.o: master_recv: reading %d bytes on %s.\n", + count,client->adapter->name)); + +- I2C_LOCK(adap); ++ down(&adap->bus); + ret = adap->algo->master_xfer(adap,&msg,1); +- I2C_UNLOCK(adap); ++ up(&adap->bus); + + DEB2(printk(KERN_DEBUG "i2c-core.o: master_recv: return:%d (count:%d, addr:0x%02x)\n", + ret, count, client->addr)); +@@ -965,6 +920,123 @@ + + /* The SMBus parts */ + ++#define POLY (0x1070U << 3) ++static u8 ++crc8(u16 data) ++{ ++ int i; ++ ++ for(i = 0; i < 8; i++) { ++ if (data & 0x8000) ++ data = data ^ POLY; ++ data = data << 1; ++ } ++ return (u8)(data >> 8); ++} ++ ++/* CRC over count bytes in the first array plus the bytes in the rest ++ array if it is non-null. rest[0] is the (length of rest) - 1 ++ and is included. */ ++u8 i2c_smbus_partial_pec(u8 crc, int count, u8 *first, u8 *rest) ++{ ++ int i; ++ ++ for(i = 0; i < count; i++) ++ crc = crc8((crc ^ first[i]) << 8); ++ if(rest != NULL) ++ for(i = 0; i <= rest[0]; i++) ++ crc = crc8((crc ^ rest[i]) << 8); ++ return crc; ++} ++ ++u8 i2c_smbus_pec(int count, u8 *first, u8 *rest) ++{ ++ return i2c_smbus_partial_pec(0, count, first, rest); ++} ++ ++/* Returns new "size" (transaction type) ++ Note that we convert byte to byte_data and byte_data to word_data ++ rather than invent new xxx_PEC transactions. */ ++int i2c_smbus_add_pec(u16 addr, u8 command, int size, ++ union i2c_smbus_data *data) ++{ ++ u8 buf[3]; ++ ++ buf[0] = addr << 1; ++ buf[1] = command; ++ switch(size) { ++ case I2C_SMBUS_BYTE: ++ data->byte = i2c_smbus_pec(2, buf, NULL); ++ size = I2C_SMBUS_BYTE_DATA; ++ break; ++ case I2C_SMBUS_BYTE_DATA: ++ buf[2] = data->byte; ++ data->word = buf[2] || ++ (i2c_smbus_pec(3, buf, NULL) << 8); ++ size = I2C_SMBUS_WORD_DATA; ++ break; ++ case I2C_SMBUS_WORD_DATA: ++ /* unsupported */ ++ break; ++ case I2C_SMBUS_BLOCK_DATA: ++ data->block[data->block[0] + 1] = ++ i2c_smbus_pec(2, buf, data->block); ++ size = I2C_SMBUS_BLOCK_DATA_PEC; ++ break; ++ } ++ return size; ++} ++ ++int i2c_smbus_check_pec(u16 addr, u8 command, int size, u8 partial, ++ union i2c_smbus_data *data) ++{ ++ u8 buf[3], rpec, cpec; ++ ++ buf[1] = command; ++ switch(size) { ++ case I2C_SMBUS_BYTE_DATA: ++ buf[0] = (addr << 1) | 1; ++ cpec = i2c_smbus_pec(2, buf, NULL); ++ rpec = data->byte; ++ break; ++ case I2C_SMBUS_WORD_DATA: ++ buf[0] = (addr << 1) | 1; ++ buf[2] = data->word & 0xff; ++ cpec = i2c_smbus_pec(3, buf, NULL); ++ rpec = data->word >> 8; ++ break; ++ case I2C_SMBUS_WORD_DATA_PEC: ++ /* unsupported */ ++ cpec = rpec = 0; ++ break; ++ case I2C_SMBUS_PROC_CALL_PEC: ++ /* unsupported */ ++ cpec = rpec = 0; ++ break; ++ case I2C_SMBUS_BLOCK_DATA_PEC: ++ buf[0] = (addr << 1); ++ buf[2] = (addr << 1) | 1; ++ cpec = i2c_smbus_pec(3, buf, data->block); ++ rpec = data->block[data->block[0] + 1]; ++ break; ++ case I2C_SMBUS_BLOCK_PROC_CALL_PEC: ++ buf[0] = (addr << 1) | 1; ++ rpec = i2c_smbus_partial_pec(partial, 1, ++ buf, data->block); ++ cpec = data->block[data->block[0] + 1]; ++ break; ++ default: ++ cpec = rpec = 0; ++ break; ++ } ++ if(rpec != cpec) { ++ DEB(printk(KERN_DEBUG "i2c-core.o: Bad PEC 0x%02x vs. 0x%02x\n", ++ rpec, cpec)); ++ return -1; ++ } ++ return 0; ++} ++ + extern s32 i2c_smbus_write_quick(struct i2c_client * client, u8 value) + { + return i2c_smbus_xfer(client->adapter,client->addr,client->flags, +@@ -983,8 +1055,9 @@ + + extern s32 i2c_smbus_write_byte(struct i2c_client * client, u8 value) + { ++ union i2c_smbus_data data; /* only for PEC */ + return i2c_smbus_xfer(client->adapter,client->addr,client->flags, +- I2C_SMBUS_WRITE,value, I2C_SMBUS_BYTE,NULL); ++ I2C_SMBUS_WRITE,value, I2C_SMBUS_BYTE,&data); + } + + extern s32 i2c_smbus_read_byte_data(struct i2c_client * client, u8 command) +@@ -1072,6 +1145,43 @@ + I2C_SMBUS_BLOCK_DATA,&data); + } + ++/* Returns the number of read bytes */ ++extern s32 i2c_smbus_block_process_call(struct i2c_client * client, ++ u8 command, u8 length, u8 *values) ++{ ++ union i2c_smbus_data data; ++ int i; ++ if (length > I2C_SMBUS_BLOCK_MAX - 1) ++ return -1; ++ data.block[0] = length; ++ for (i = 1; i <= length; i++) ++ data.block[i] = values[i-1]; ++ if(i2c_smbus_xfer(client->adapter,client->addr,client->flags, ++ I2C_SMBUS_WRITE, command, ++ I2C_SMBUS_BLOCK_PROC_CALL, &data)) ++ return -1; ++ for (i = 1; i <= data.block[0]; i++) ++ values[i-1] = data.block[i]; ++ return data.block[0]; ++} ++ ++/* Returns the number of read bytes */ ++extern s32 i2c_smbus_read_i2c_block_data(struct i2c_client * client, ++ u8 command, u8 *values) ++{ ++ union i2c_smbus_data data; ++ int i; ++ if (i2c_smbus_xfer(client->adapter,client->addr,client->flags, ++ I2C_SMBUS_READ,command, ++ I2C_SMBUS_I2C_BLOCK_DATA,&data)) ++ return -1; ++ else { ++ for (i = 1; i <= data.block[0]; i++) ++ values[i-1] = data.block[i]; ++ return data.block[0]; ++ } ++} ++ + extern s32 i2c_smbus_write_i2c_block_data(struct i2c_client * client, + u8 command, u8 length, u8 *values) + { +@@ -1098,13 +1208,13 @@ + need to use only one message; when reading, we need two. We initialize + most things with sane defaults, to keep the code below somewhat + simpler. */ +- unsigned char msgbuf0[34]; +- unsigned char msgbuf1[34]; ++ unsigned char msgbuf0[I2C_SMBUS_BLOCK_MAX+2]; ++ unsigned char msgbuf1[I2C_SMBUS_BLOCK_MAX+2]; + int num = read_write == I2C_SMBUS_READ?2:1; + struct i2c_msg msg[2] = { { addr, flags, 1, msgbuf0 }, + { addr, flags | I2C_M_RD, 0, msgbuf1 } + }; +- int i; ++ int i, len; + + msgbuf0[0] = command; + switch(size) { +@@ -1140,16 +1250,30 @@ + break; + case I2C_SMBUS_PROC_CALL: + num = 2; /* Special case */ ++ read_write = I2C_SMBUS_READ; + msg[0].len = 3; + msg[1].len = 2; + msgbuf0[1] = data->word & 0xff; + msgbuf0[2] = (data->word >> 8) & 0xff; + break; + case I2C_SMBUS_BLOCK_DATA: ++ case I2C_SMBUS_BLOCK_DATA_PEC: + if (read_write == I2C_SMBUS_READ) { +- printk(KERN_ERR "i2c-core.o: Block read not supported " +- "under I2C emulation!\n"); +- return -1; ++ /* I2C_FUNC_SMBUS_EMUL doesn't include I2C_FUNC_SMBUS_READ_BLOCK_DATA */ ++ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_BLOCK_DATA)) { ++ printk(KERN_ERR "i2c-core.o: Block read not supported " ++ "under I2C emulation!\n"); ++ return -1; ++ } ++ /* set send message */ ++ msg[0].len = 1; ++ /* set recv message */ ++ msg[1].flags |= I2C_M_RECV_LEN; ++ msg[1].len = I2C_SMBUS_BLOCK_MAX + 1; ++ if (size == I2C_SMBUS_BLOCK_DATA_PEC) { ++ msg[1].len++; ++ msg[1].flags |= I2C_M_RECV_PEC; ++ } + } else { + msg[0].len = data->block[0] + 2; + if (msg[0].len > I2C_SMBUS_BLOCK_MAX + 2) { +@@ -1158,10 +1282,57 @@ + data->block[0]); + return -1; + } ++ if(size == I2C_SMBUS_BLOCK_DATA_PEC) ++ (msg[0].len)++; + for (i = 1; i <= msg[0].len; i++) + msgbuf0[i] = data->block[i-1]; + } + break; ++ case I2C_SMBUS_BLOCK_PROC_CALL: ++ case I2C_SMBUS_BLOCK_PROC_CALL_PEC: ++ /* I2C_FUNC_SMBUS_EMUL doesn't include I2C_FUNC_SMBUS_BLOCK_PROC_CALL */ ++ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BLOCK_PROC_CALL)) { ++ printk(KERN_ERR "i2c-core.o: adapter doesn't support block process call!\n"); ++ return -1; ++ } ++ ++ /* Another special case */ ++ num = 2; ++ read_write = I2C_SMBUS_READ; ++ ++ /* set send message */ ++ msg[0].len = data->block[0] + 2; ++ if (msg[0].len > I2C_SMBUS_BLOCK_MAX + 2) { ++ printk(KERN_ERR "i2c-core.o: smbus_access called with " ++ "invalid block write size (%d)\n", data->block[0]); ++ return -1; ++ } ++ for (i = 1; i <= msg[0].len; i++) ++ msgbuf0[i] = data->block[i-1]; ++ ++ /* set recv message */ ++ msg[1].flags |= I2C_M_RECV_LEN; ++ msg[1].len = I2C_SMBUS_BLOCK_MAX + 1; ++ if (size == I2C_SMBUS_BLOCK_PROC_CALL_PEC) { ++ msg[1].len++; ++ msg[1].flags |= I2C_M_RECV_PEC; ++ } ++ break; ++ case I2C_SMBUS_I2C_BLOCK_DATA: ++ if (read_write == I2C_SMBUS_READ) { ++ msg[1].len = I2C_SMBUS_I2C_BLOCK_MAX; ++ } else { ++ msg[0].len = data->block[0] + 1; ++ if (msg[0].len > I2C_SMBUS_I2C_BLOCK_MAX + 1) { ++ printk("i2c-core.o: i2c_smbus_xfer_emulated called with " ++ "invalid block write size (%d)\n", ++ data->block[0]); ++ return -1; ++ } ++ for (i = 1; i <= data->block[0]; i++) ++ msgbuf0[i] = data->block[i]; ++ } ++ break; + default: + printk(KERN_ERR "i2c-core.o: smbus_access called with invalid size (%d)\n", + size); +@@ -1183,25 +1354,72 @@ + case I2C_SMBUS_PROC_CALL: + data->word = msgbuf1[0] | (msgbuf1[1] << 8); + break; ++ case I2C_SMBUS_I2C_BLOCK_DATA: ++ /* fixed at 32 for now */ ++ data->block[0] = I2C_SMBUS_I2C_BLOCK_MAX; ++ for (i = 0; i < I2C_SMBUS_I2C_BLOCK_MAX; i++) ++ data->block[i+1] = msgbuf1[i]; ++ break; ++ case I2C_SMBUS_BLOCK_DATA: ++ case I2C_SMBUS_BLOCK_PROC_CALL: ++ case I2C_SMBUS_BLOCK_DATA_PEC: ++ case I2C_SMBUS_BLOCK_PROC_CALL_PEC: ++ len = msgbuf1[0] + 1; ++ if(size == I2C_SMBUS_BLOCK_DATA_PEC || ++ size == I2C_SMBUS_BLOCK_PROC_CALL_PEC) ++ len++; ++ for (i = 0; i < len; i++) ++ data->block[i] = msgbuf1[i]; ++ break; + } + return 0; + } + + +-s32 i2c_smbus_xfer(struct i2c_adapter * adapter, u16 addr, unsigned short flags, ++s32 i2c_smbus_xfer(struct i2c_adapter * adap, u16 addr, unsigned short flags, + char read_write, u8 command, int size, + union i2c_smbus_data * data) + { + s32 res; +- flags = flags & I2C_M_TEN; +- if (adapter->algo->smbus_xfer) { +- I2C_LOCK(adapter); +- res = adapter->algo->smbus_xfer(adapter,addr,flags,read_write, ++ int swpec = 0; ++ u8 partial = 0; ++ ++ flags &= I2C_M_TEN | I2C_CLIENT_PEC; ++ if((flags & I2C_CLIENT_PEC) && ++ !(i2c_check_functionality(adap, I2C_FUNC_SMBUS_HWPEC_CALC))) { ++ swpec = 1; ++ if(read_write == I2C_SMBUS_READ && ++ size == I2C_SMBUS_BLOCK_DATA) ++ size = I2C_SMBUS_BLOCK_DATA_PEC; ++ else if(size == I2C_SMBUS_PROC_CALL) ++ size = I2C_SMBUS_PROC_CALL_PEC; ++ else if(size == I2C_SMBUS_BLOCK_PROC_CALL) { ++ i2c_smbus_add_pec(addr, command, ++ I2C_SMBUS_BLOCK_DATA, data); ++ partial = data->block[data->block[0] + 1]; ++ size = I2C_SMBUS_BLOCK_PROC_CALL_PEC; ++ } else if(read_write == I2C_SMBUS_WRITE && ++ size != I2C_SMBUS_QUICK && ++ size != I2C_SMBUS_I2C_BLOCK_DATA) ++ size = i2c_smbus_add_pec(addr, command, size, data); ++ } ++ ++ if (adap->algo->smbus_xfer) { ++ down(&adap->bus); ++ res = adap->algo->smbus_xfer(adap,addr,flags,read_write, + command,size,data); +- I2C_UNLOCK(adapter); ++ up(&adap->bus); + } else +- res = i2c_smbus_xfer_emulated(adapter,addr,flags,read_write, ++ res = i2c_smbus_xfer_emulated(adap,addr,flags,read_write, + command,size,data); ++ ++ if(res >= 0 && swpec && ++ size != I2C_SMBUS_QUICK && size != I2C_SMBUS_I2C_BLOCK_DATA && ++ (read_write == I2C_SMBUS_READ || size == I2C_SMBUS_PROC_CALL_PEC || ++ size == I2C_SMBUS_BLOCK_PROC_CALL_PEC)) { ++ if(i2c_smbus_check_pec(addr, command, size, partial, data)) ++ return -1; ++ } + return res; + } + +@@ -1228,143 +1446,37 @@ + printk(KERN_INFO "i2c-core.o: i2c core module version %s (%s)\n", I2C_VERSION, I2C_DATE); + memset(adapters,0,sizeof(adapters)); + memset(drivers,0,sizeof(drivers)); +- adap_count=0; +- driver_count=0; + +- init_MUTEX(&adap_lock); +- init_MUTEX(&driver_lock); +- +- i2cproc_init(); +- ++#ifdef CONFIG_PROC_FS ++ return i2cproc_init(); ++#else + return 0; +-} +- +-#ifndef MODULE +-#ifdef CONFIG_I2C_CHARDEV +- extern int i2c_dev_init(void); +-#endif +-#ifdef CONFIG_I2C_ALGOBIT +- extern int i2c_algo_bit_init(void); +-#endif +-#ifdef CONFIG_I2C_PHILIPSPAR +- extern int i2c_bitlp_init(void); +-#endif +-#ifdef CONFIG_I2C_ELV +- extern int i2c_bitelv_init(void); +-#endif +-#ifdef CONFIG_I2C_VELLEMAN +- extern int i2c_bitvelle_init(void); +-#endif +-#ifdef CONFIG_I2C_BITVIA +- extern int i2c_bitvia_init(void); +-#endif +- +-#ifdef CONFIG_I2C_ALGOPCF +- extern int i2c_algo_pcf_init(void); +-#endif +-#ifdef CONFIG_I2C_ELEKTOR +- extern int i2c_pcfisa_init(void); +-#endif +- +-#ifdef CONFIG_I2C_ALGO8XX +- extern int i2c_algo_8xx_init(void); +-#endif +-#ifdef CONFIG_I2C_RPXLITE +- extern int i2c_rpx_init(void); +-#endif +- +-#ifdef CONFIG_I2C_ALGO_SIBYTE +- extern int i2c_algo_sibyte_init(void); +- extern int i2c_sibyte_init(void); +-#endif +-#ifdef CONFIG_I2C_MAX1617 +- extern int i2c_max1617_init(void); +-#endif +-#ifdef CONFIG_I2C_ALGO_AU1550 +- extern int i2c_pb1550_init(void); + #endif ++} + +-#ifdef CONFIG_I2C_PROC +- extern int sensors_init(void); ++static void __exit i2c_exit(void) ++{ ++#ifdef CONFIG_PROC_FS ++ i2cproc_cleanup(); + #endif ++} + +-/* This is needed for automatic patch generation: sensors code starts here */ +-/* This is needed for automatic patch generation: sensors code ends here */ +- ++/* leave this in for now simply to make patching easier so we don't have ++ to remove the call in drivers/char/mem.c */ + int __init i2c_init_all(void) + { +- /* --------------------- global ----- */ +- i2c_init(); +- +-#ifdef CONFIG_I2C_CHARDEV +- i2c_dev_init(); +-#endif +- /* --------------------- bit -------- */ +-#ifdef CONFIG_I2C_ALGOBIT +- i2c_algo_bit_init(); +-#endif +-#ifdef CONFIG_I2C_PHILIPSPAR +- i2c_bitlp_init(); +-#endif +-#ifdef CONFIG_I2C_ELV +- i2c_bitelv_init(); +-#endif +-#ifdef CONFIG_I2C_VELLEMAN +- i2c_bitvelle_init(); +-#endif +- +- /* --------------------- pcf -------- */ +-#ifdef CONFIG_I2C_ALGOPCF +- i2c_algo_pcf_init(); +-#endif +-#ifdef CONFIG_I2C_ELEKTOR +- i2c_pcfisa_init(); +-#endif +- +- /* --------------------- 8xx -------- */ +-#ifdef CONFIG_I2C_ALGO8XX +- i2c_algo_8xx_init(); +-#endif +-#ifdef CONFIG_I2C_RPXLITE +- i2c_rpx_init(); +-#endif +- +- /* --------------------- SiByte -------- */ +-#ifdef CONFIG_I2C_ALGO_SIBYTE +- i2c_algo_sibyte_init(); +- i2c_sibyte_init(); +-#endif +-#ifdef CONFIG_I2C_MAX1617 +- i2c_max1617_init(); +-#endif +- +-#ifdef CONFIG_I2C_ALGO_AU1550 +- i2c_pb1550_init(); +-#endif +- +- /* -------------- proc interface ---- */ +-#ifdef CONFIG_I2C_PROC +- sensors_init(); +-#endif +-/* This is needed for automatic patch generation: sensors code starts here */ +-/* This is needed for automatic patch generation: sensors code ends here */ +- + return 0; + } + +-#endif +- +- +- + EXPORT_SYMBOL(i2c_add_adapter); + EXPORT_SYMBOL(i2c_del_adapter); + EXPORT_SYMBOL(i2c_add_driver); + EXPORT_SYMBOL(i2c_del_driver); + EXPORT_SYMBOL(i2c_attach_client); + EXPORT_SYMBOL(i2c_detach_client); +-EXPORT_SYMBOL(i2c_inc_use_client); +-EXPORT_SYMBOL(i2c_dec_use_client); ++#if 0 + EXPORT_SYMBOL(i2c_get_client); ++#endif + EXPORT_SYMBOL(i2c_use_client); + EXPORT_SYMBOL(i2c_release_client); + EXPORT_SYMBOL(i2c_check_addr); +@@ -1388,11 +1500,12 @@ + EXPORT_SYMBOL(i2c_smbus_process_call); + EXPORT_SYMBOL(i2c_smbus_read_block_data); + EXPORT_SYMBOL(i2c_smbus_write_block_data); ++EXPORT_SYMBOL(i2c_smbus_read_i2c_block_data); ++EXPORT_SYMBOL(i2c_smbus_write_i2c_block_data); + + EXPORT_SYMBOL(i2c_get_functionality); + EXPORT_SYMBOL(i2c_check_functionality); + +-#ifdef MODULE + MODULE_AUTHOR("Simon G. Vogl <simon@tk.uni-linz.ac.at>"); + MODULE_DESCRIPTION("I2C-Bus main module"); + MODULE_LICENSE("GPL"); +@@ -1400,13 +1513,5 @@ + MODULE_PARM(i2c_debug, "i"); + MODULE_PARM_DESC(i2c_debug,"debug level"); + +-int init_module(void) +-{ +- return i2c_init(); +-} +- +-void cleanup_module(void) +-{ +- i2cproc_cleanup(); +-} +-#endif ++module_init(i2c_init); ++module_exit(i2c_exit); +--- linux-old/drivers/i2c/i2c-dev.c Tue Jan 20 15:10:31 2004 ++++ linux/drivers/i2c/i2c-dev.c Mon Dec 13 19:26:32 2004 +@@ -28,9 +28,8 @@ + /* The devfs code is contributed by Philipp Matthias Hahn + <pmhahn@titan.lahn.de> */ + +-/* $Id: i2c-dev.c,v 1.40 2001/08/25 01:28:01 mds Exp $ */ ++/* $Id: i2c-dev.c,v 1.57 2003/12/22 20:03:39 khali Exp $ */ + +-#include <linux/config.h> + #include <linux/kernel.h> + #include <linux/module.h> + #include <linux/fs.h> +@@ -39,21 +38,14 @@ + #ifdef CONFIG_DEVFS_FS + #include <linux/devfs_fs_kernel.h> + #endif +- +- +-/* If you want debugging uncomment: */ +-/* #define DEBUG */ +- + #include <linux/init.h> +-#include <asm/uaccess.h> +- + #include <linux/i2c.h> + #include <linux/i2c-dev.h> ++#include <asm/uaccess.h> ++ ++/* If you want debugging uncomment: */ ++/* #define DEBUG */ + +-#ifdef MODULE +-extern int init_module(void); +-extern int cleanup_module(void); +-#endif /* def MODULE */ + + /* struct file_operations changed too often in the 2.1 series for nice code */ + +@@ -73,22 +65,14 @@ + static int i2cdev_command(struct i2c_client *client, unsigned int cmd, + void *arg); + +-#ifdef MODULE +-static +-#else +-extern +-#endif +- int __init i2c_dev_init(void); +-static int i2cdev_cleanup(void); +- + static struct file_operations i2cdev_fops = { +- owner: THIS_MODULE, +- llseek: no_llseek, +- read: i2cdev_read, +- write: i2cdev_write, +- ioctl: i2cdev_ioctl, +- open: i2cdev_open, +- release: i2cdev_release, ++ .owner = THIS_MODULE, ++ .llseek = no_llseek, ++ .read = i2cdev_read, ++ .write = i2cdev_write, ++ .ioctl = i2cdev_ioctl, ++ .open = i2cdev_open, ++ .release = i2cdev_release, + }; + + #define I2CDEV_ADAPS_MAX I2C_ADAP_MAX +@@ -99,28 +83,22 @@ + #endif + + static struct i2c_driver i2cdev_driver = { +- name: "i2c-dev dummy driver", +- id: I2C_DRIVERID_I2CDEV, +- flags: I2C_DF_DUMMY, +- attach_adapter: i2cdev_attach_adapter, +- detach_client: i2cdev_detach_client, +- command: i2cdev_command, +-/* inc_use: NULL, +- dec_use: NULL, */ ++ .owner = THIS_MODULE, /* not really used */ ++ .name = "i2c-dev dummy driver", ++ .id = I2C_DRIVERID_I2CDEV, ++ .flags = I2C_DF_DUMMY, ++ .attach_adapter = i2cdev_attach_adapter, ++ .detach_client = i2cdev_detach_client, ++ .command = i2cdev_command, + }; + + static struct i2c_client i2cdev_client_template = { +- name: "I2C /dev entry", +- id: 1, +- flags: 0, +- addr: -1, +-/* adapter: NULL, */ +- driver: &i2cdev_driver, +-/* data: NULL */ ++ .name = "I2C /dev entry", ++ .id = 1, ++ .addr = -1, ++ .driver = &i2cdev_driver, + }; + +-static int i2cdev_initialized; +- + static ssize_t i2cdev_read (struct file *file, char *buf, size_t count, + loff_t *offset) + { +@@ -142,7 +120,7 @@ + return -ENOMEM; + + #ifdef DEBUG +- printk(KERN_DEBUG "i2c-dev.o: i2c-%d reading %d bytes.\n",MINOR(inode->i_rdev), ++ printk(KERN_DEBUG "i2c-dev.o: i2c-%d reading %d bytes.\n",minor(inode->i_rdev), + count); + #endif + +@@ -177,7 +155,7 @@ + } + + #ifdef DEBUG +- printk(KERN_DEBUG "i2c-dev.o: i2c-%d writing %d bytes.\n",MINOR(inode->i_rdev), ++ printk(KERN_DEBUG "i2c-dev.o: i2c-%d writing %d bytes.\n",minor(inode->i_rdev), + count); + #endif + ret = i2c_master_send(client,tmp,count); +@@ -199,7 +177,7 @@ + + #ifdef DEBUG + printk(KERN_DEBUG "i2c-dev.o: i2c-%d ioctl, cmd: 0x%x, arg: %lx.\n", +- MINOR(inode->i_rdev),cmd, arg); ++ minor(inode->i_rdev),cmd, arg); + #endif /* DEBUG */ + + switch ( cmd ) { +@@ -218,6 +196,12 @@ + else + client->flags &= ~I2C_M_TEN; + return 0; ++ case I2C_PEC: ++ if (arg) ++ client->flags |= I2C_CLIENT_PEC; ++ else ++ client->flags &= ~I2C_CLIENT_PEC; ++ return 0; + case I2C_FUNCS: + funcs = i2c_get_functionality(client->adapter); + return (copy_to_user((unsigned long *)arg,&funcs, +@@ -318,7 +302,8 @@ + (data_arg.size != I2C_SMBUS_WORD_DATA) && + (data_arg.size != I2C_SMBUS_PROC_CALL) && + (data_arg.size != I2C_SMBUS_BLOCK_DATA) && +- (data_arg.size != I2C_SMBUS_I2C_BLOCK_DATA)) { ++ (data_arg.size != I2C_SMBUS_I2C_BLOCK_DATA) && ++ (data_arg.size != I2C_SMBUS_BLOCK_PROC_CALL)) { + #ifdef DEBUG + printk(KERN_DEBUG "i2c-dev.o: size out of range (%x) in ioctl I2C_SMBUS.\n", + data_arg.size); +@@ -361,10 +346,11 @@ + else if ((data_arg.size == I2C_SMBUS_WORD_DATA) || + (data_arg.size == I2C_SMBUS_PROC_CALL)) + datasize = sizeof(data_arg.data->word); +- else /* size == I2C_SMBUS_BLOCK_DATA */ ++ else /* size == smbus block, i2c block, or block proc. call */ + datasize = sizeof(data_arg.data->block); + + if ((data_arg.size == I2C_SMBUS_PROC_CALL) || ++ (data_arg.size == I2C_SMBUS_BLOCK_PROC_CALL) || + (data_arg.read_write == I2C_SMBUS_WRITE)) { + if (copy_from_user(&temp, data_arg.data, datasize)) + return -EFAULT; +@@ -373,6 +359,7 @@ + data_arg.read_write, + data_arg.command,data_arg.size,&temp); + if (! res && ((data_arg.size == I2C_SMBUS_PROC_CALL) || ++ (data_arg.size == I2C_SMBUS_BLOCK_PROC_CALL) || + (data_arg.read_write == I2C_SMBUS_READ))) { + if (copy_to_user(data_arg.data, &temp, datasize)) + return -EFAULT; +@@ -387,7 +374,7 @@ + + int i2cdev_open (struct inode *inode, struct file *file) + { +- unsigned int minor = MINOR(inode->i_rdev); ++ unsigned int minor = minor(inode->i_rdev); + struct i2c_client *client; + + if ((minor >= I2CDEV_ADAPS_MAX) || ! (i2cdev_adaps[minor])) { +@@ -403,11 +390,13 @@ + if(! (client = kmalloc(sizeof(struct i2c_client),GFP_KERNEL))) + return -ENOMEM; + memcpy(client,&i2cdev_client_template,sizeof(struct i2c_client)); ++ ++ /* registered with adapter, passed as client to user */ + client->adapter = i2cdev_adaps[minor]; + file->private_data = client; + +- if (i2cdev_adaps[minor]->inc_use) +- i2cdev_adaps[minor]->inc_use(i2cdev_adaps[minor]); ++ if(client->adapter->owner) ++ __MOD_INC_USE_COUNT(client->adapter->owner); + + #ifdef DEBUG + printk(KERN_DEBUG "i2c-dev.o: opened i2c-%d\n",minor); +@@ -417,16 +406,19 @@ + + static int i2cdev_release (struct inode *inode, struct file *file) + { +- unsigned int minor = MINOR(inode->i_rdev); +- kfree(file->private_data); +- file->private_data=NULL; ++ struct i2c_client *client; ++#ifdef DEBUG ++ unsigned int minor = minor(inode->i_rdev); ++#endif ++ ++ client = file->private_data; ++ file->private_data = NULL; ++ if(client->adapter->owner) ++ __MOD_DEC_USE_COUNT(client->adapter->owner); ++ kfree(client); + #ifdef DEBUG + printk(KERN_DEBUG "i2c-dev.o: Closed: i2c-%d\n", minor); + #endif +- lock_kernel(); +- if (i2cdev_adaps[minor]->dec_use) +- i2cdev_adaps[minor]->dec_use(i2cdev_adaps[minor]); +- unlock_kernel(); + return 0; + } + +@@ -451,7 +443,7 @@ + devfs_i2c[i] = devfs_register (devfs_handle, name, + DEVFS_FL_DEFAULT, I2C_MAJOR, i, + S_IFCHR | S_IRUSR | S_IWUSR, +- &i2cdev_fops, NULL); ++ &i2cdev_fops, adap); + #endif + printk(KERN_DEBUG "i2c-dev.o: Registered '%s' as minor %d\n",adap->name,i); + } else { +@@ -479,13 +471,12 @@ + return -1; + } + +-int __init i2c_dev_init(void) ++static int __init i2c_dev_init(void) + { + int res; + + printk(KERN_INFO "i2c-dev.o: i2c /dev entries driver module version %s (%s)\n", I2C_VERSION, I2C_DATE); + +- i2cdev_initialized = 0; + #ifdef CONFIG_DEVFS_FS + if (devfs_register_chrdev(I2C_MAJOR, "i2c", &i2cdev_fops)) { + #else +@@ -498,63 +489,31 @@ + #ifdef CONFIG_DEVFS_FS + devfs_handle = devfs_mk_dir(NULL, "i2c", NULL); + #endif +- i2cdev_initialized ++; +- + if ((res = i2c_add_driver(&i2cdev_driver))) { + printk(KERN_ERR "i2c-dev.o: Driver registration failed, module not inserted.\n"); +- i2cdev_cleanup(); ++#ifdef CONFIG_DEVFS_FS ++ devfs_unregister(devfs_handle); ++#endif ++ unregister_chrdev(I2C_MAJOR,"i2c"); + return res; + } +- i2cdev_initialized ++; + return 0; + } + +-int i2cdev_cleanup(void) ++static void __exit i2c_dev_exit(void) + { +- int res; +- +- if (i2cdev_initialized >= 2) { +- if ((res = i2c_del_driver(&i2cdev_driver))) { +- printk("i2c-dev.o: Driver deregistration failed, " +- "module not removed.\n"); +- return res; +- } +- i2cdev_initialized --; +- } +- +- if (i2cdev_initialized >= 1) { ++ i2c_del_driver(&i2cdev_driver); + #ifdef CONFIG_DEVFS_FS +- devfs_unregister(devfs_handle); +- if ((res = devfs_unregister_chrdev(I2C_MAJOR, "i2c"))) { +-#else +- if ((res = unregister_chrdev(I2C_MAJOR,"i2c"))) { ++ devfs_unregister(devfs_handle); + #endif +- printk("i2c-dev.o: unable to release major %d for i2c bus\n", +- I2C_MAJOR); +- return res; +- } +- i2cdev_initialized --; +- } +- return 0; ++ unregister_chrdev(I2C_MAJOR,"i2c"); + } + + EXPORT_NO_SYMBOLS; + +-#ifdef MODULE +- + MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl> and Simon G. Vogl <simon@tk.uni-linz.ac.at>"); + MODULE_DESCRIPTION("I2C /dev entries driver"); + MODULE_LICENSE("GPL"); + +-int init_module(void) +-{ +- return i2c_dev_init(); +-} +- +-int cleanup_module(void) +-{ +- return i2cdev_cleanup(); +-} +- +-#endif /* def MODULE */ +- ++module_init(i2c_dev_init); ++module_exit(i2c_dev_exit); +--- linux-old/include/linux/i2c-dev.h Sat Jul 5 03:23:47 2003 ++++ linux/include/linux/i2c-dev.h Mon Dec 13 19:26:32 2004 +@@ -19,14 +19,16 @@ + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +-/* $Id: i2c-dev.h,v 1.9 2001/08/15 03:04:58 mds Exp $ */ +- +-#ifndef I2C_DEV_H +-#define I2C_DEV_H ++/* $Id: i2c-dev.h,v 1.14 2003/07/25 07:56:42 khali Exp $ */ + ++#ifndef _LINUX_I2C_DEV_H ++#define _LINUX_I2C_DEV_H + + #include <linux/types.h> +-#include <linux/i2c.h> ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,18) ++#define minor(d) MINOR(d) ++#endif + + /* Some IOCTL commands are defined in <linux/i2c.h> */ + /* Note: 10-bit addresses are NOT supported! */ +@@ -45,137 +47,4 @@ + __u32 nmsgs; /* number of i2c_msgs */ + }; + +-#ifndef __KERNEL__ +- +-#include <sys/ioctl.h> +- +-static inline __s32 i2c_smbus_access(int file, char read_write, __u8 command, +- int size, union i2c_smbus_data *data) +-{ +- struct i2c_smbus_ioctl_data args; +- +- args.read_write = read_write; +- args.command = command; +- args.size = size; +- args.data = data; +- return ioctl(file,I2C_SMBUS,&args); +-} +- +- +-static inline __s32 i2c_smbus_write_quick(int file, __u8 value) +-{ +- return i2c_smbus_access(file,value,0,I2C_SMBUS_QUICK,NULL); +-} +- +-static inline __s32 i2c_smbus_read_byte(int file) +-{ +- union i2c_smbus_data data; +- if (i2c_smbus_access(file,I2C_SMBUS_READ,0,I2C_SMBUS_BYTE,&data)) +- return -1; +- else +- return 0x0FF & data.byte; +-} +- +-static inline __s32 i2c_smbus_write_byte(int file, __u8 value) +-{ +- return i2c_smbus_access(file,I2C_SMBUS_WRITE,value, +- I2C_SMBUS_BYTE,NULL); +-} +- +-static inline __s32 i2c_smbus_read_byte_data(int file, __u8 command) +-{ +- union i2c_smbus_data data; +- if (i2c_smbus_access(file,I2C_SMBUS_READ,command, +- I2C_SMBUS_BYTE_DATA,&data)) +- return -1; +- else +- return 0x0FF & data.byte; +-} +- +-static inline __s32 i2c_smbus_write_byte_data(int file, __u8 command, +- __u8 value) +-{ +- union i2c_smbus_data data; +- data.byte = value; +- return i2c_smbus_access(file,I2C_SMBUS_WRITE,command, +- I2C_SMBUS_BYTE_DATA, &data); +-} +- +-static inline __s32 i2c_smbus_read_word_data(int file, __u8 command) +-{ +- union i2c_smbus_data data; +- if (i2c_smbus_access(file,I2C_SMBUS_READ,command, +- I2C_SMBUS_WORD_DATA,&data)) +- return -1; +- else +- return 0x0FFFF & data.word; +-} +- +-static inline __s32 i2c_smbus_write_word_data(int file, __u8 command, +- __u16 value) +-{ +- union i2c_smbus_data data; +- data.word = value; +- return i2c_smbus_access(file,I2C_SMBUS_WRITE,command, +- I2C_SMBUS_WORD_DATA, &data); +-} +- +-static inline __s32 i2c_smbus_process_call(int file, __u8 command, __u16 value) +-{ +- union i2c_smbus_data data; +- data.word = value; +- if (i2c_smbus_access(file,I2C_SMBUS_WRITE,command, +- I2C_SMBUS_PROC_CALL,&data)) +- return -1; +- else +- return 0x0FFFF & data.word; +-} +- +- +-/* Returns the number of read bytes */ +-static inline __s32 i2c_smbus_read_block_data(int file, __u8 command, +- __u8 *values) +-{ +- union i2c_smbus_data data; +- int i; +- if (i2c_smbus_access(file,I2C_SMBUS_READ,command, +- I2C_SMBUS_BLOCK_DATA,&data)) +- return -1; +- else { +- for (i = 1; i <= data.block[0]; i++) +- values[i-1] = data.block[i]; +- return data.block[0]; +- } +-} +- +-static inline __s32 i2c_smbus_write_block_data(int file, __u8 command, +- __u8 length, __u8 *values) +-{ +- union i2c_smbus_data data; +- int i; +- if (length > 32) +- length = 32; +- for (i = 1; i <= length; i++) +- data.block[i] = values[i-1]; +- data.block[0] = length; +- return i2c_smbus_access(file,I2C_SMBUS_WRITE,command, +- I2C_SMBUS_BLOCK_DATA, &data); +-} +- +-static inline __s32 i2c_smbus_write_i2c_block_data(int file, __u8 command, +- __u8 length, __u8 *values) +-{ +- union i2c_smbus_data data; +- int i; +- if (length > 32) +- length = 32; +- for (i = 1; i <= length; i++) +- data.block[i] = values[i-1]; +- data.block[0] = length; +- return i2c_smbus_access(file,I2C_SMBUS_WRITE,command, +- I2C_SMBUS_I2C_BLOCK_DATA, &data); +-} +- +-#endif /* ndef __KERNEL__ */ +- +-#endif ++#endif /* _LINUX_I2C_DEV_H */ +--- linux-old/drivers/i2c/i2c-elektor.c Tue Jan 20 15:10:31 2004 ++++ linux/drivers/i2c/i2c-elektor.c Mon Dec 13 19:26:33 2004 +@@ -31,23 +31,22 @@ + #include <linux/delay.h> + #include <linux/slab.h> + #include <linux/init.h> ++#include <linux/interrupt.h> + #include <linux/pci.h> +-#include <asm/irq.h> +-#include <asm/io.h> +- ++#include <linux/wait.h> + #include <linux/i2c.h> + #include <linux/i2c-algo-pcf.h> +-#include <linux/i2c-elektor.h> +-#include "i2c-pcf8584.h" ++#include <asm/io.h> ++#include <asm/irq.h> + + #define DEFAULT_BASE 0x330 + +-static int base = 0; +-static int irq = 0; ++static int base; ++static int irq; + static int clock = 0x1c; + static int own = 0x55; +-static int mmapped = 0; +-static int i2c_debug = 0; ++static int mmapped; ++static int i2c_debug; + + /* vdovikin: removed static struct i2c_pcf_isa gpi; code - + this module in real supports only one device, due to missing arguments +@@ -56,6 +55,7 @@ + + static wait_queue_head_t pcf_wait; + static int pcf_pending; ++static spinlock_t irq_driver_lock = SPIN_LOCK_UNLOCKED; + + /* ----- global defines ----------------------------------------------- */ + #define DEB(x) if (i2c_debug>=1) x +@@ -63,13 +63,24 @@ + #define DEB3(x) if (i2c_debug>=3) x + #define DEBE(x) x /* error messages */ + ++ ++/* compatibility */ ++#ifndef isa_readb ++#define isa_readb readb ++#endif ++ ++#ifndef isa_writeb ++#define isa_writeb writeb ++#endif ++ + /* ----- local functions ---------------------------------------------- */ + + static void pcf_isa_setbyte(void *data, int ctl, int val) + { + int address = ctl ? (base + 1) : base; + +- if (ctl && irq) { ++ /* enable irq if any specified for serial operation */ ++ if (ctl && irq && (val & I2C_PCF_ESO)) { + val |= I2C_PCF_ENI; + } + +@@ -81,10 +92,10 @@ + break; + case 2: /* double mapped I/O needed for UP2000 board, + I don't know why this... */ +- writeb(val, address); ++ isa_writeb(val, address); + /* fall */ + case 1: /* memory mapped I/O */ +- writeb(val, address); ++ isa_writeb(val, address); + break; + } + } +@@ -92,7 +103,7 @@ + static int pcf_isa_getbyte(void *data, int ctl) + { + int address = ctl ? (base + 1) : base; +- int val = mmapped ? readb(address) : inb(address); ++ int val = mmapped ? isa_readb(address) : inb(address); + + DEB3(printk(KERN_DEBUG "i2c-elektor.o: Read 0x%X 0x%02X\n", address, val)); + +@@ -115,12 +126,12 @@ + int timeout = 2; + + if (irq > 0) { +- cli(); ++ spin_lock_irq(&irq_driver_lock); + if (pcf_pending == 0) { + interruptible_sleep_on_timeout(&pcf_wait, timeout*HZ ); + } else + pcf_pending = 0; +- sti(); ++ spin_unlock_irq(&irq_driver_lock); + } else { + udelay(100); + } +@@ -136,13 +147,11 @@ + static int pcf_isa_init(void) + { + if (!mmapped) { +- if (check_region(base, 2) < 0 ) { ++ if (!request_region(base, 2, "i2c (isa bus adapter)")) { + printk(KERN_ERR + "i2c-elektor.o: requested I/O region (0x%X:2) " + "is in use.\n", base); + return -ENODEV; +- } else { +- request_region(base, 2, "i2c (isa bus adapter)"); + } + } + if (irq > 0) { +@@ -156,70 +165,29 @@ + } + + +-static void __exit pcf_isa_exit(void) +-{ +- if (irq > 0) { +- disable_irq(irq); +- free_irq(irq, 0); +- } +- if (!mmapped) { +- release_region(base , 2); +- } +-} +- +- +-static int pcf_isa_reg(struct i2c_client *client) +-{ +- return 0; +-} +- +- +-static int pcf_isa_unreg(struct i2c_client *client) +-{ +- return 0; +-} +- +-static void pcf_isa_inc_use(struct i2c_adapter *adap) +-{ +-#ifdef MODULE +- MOD_INC_USE_COUNT; +-#endif +-} +- +-static void pcf_isa_dec_use(struct i2c_adapter *adap) +-{ +-#ifdef MODULE +- MOD_DEC_USE_COUNT; +-#endif +-} +- +- + /* ------------------------------------------------------------------------ + * 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_pcf_data pcf_isa_data = { +- NULL, +- pcf_isa_setbyte, +- pcf_isa_getbyte, +- pcf_isa_getown, +- pcf_isa_getclock, +- pcf_isa_waitforpin, +- 10, 10, 100, /* waits, timeout */ ++ .setpcf = pcf_isa_setbyte, ++ .getpcf = pcf_isa_getbyte, ++ .getown = pcf_isa_getown, ++ .getclock = pcf_isa_getclock, ++ .waitforpin = pcf_isa_waitforpin, ++ .udelay = 10, ++ .mdelay = 10, ++ .timeout = HZ, + }; + + static struct i2c_adapter pcf_isa_ops = { +- "PCF8584 ISA adapter", +- I2C_HW_P_ELEK, +- NULL, +- &pcf_isa_data, +- pcf_isa_inc_use, +- pcf_isa_dec_use, +- pcf_isa_reg, +- pcf_isa_unreg, ++ .owner = THIS_MODULE, ++ .name = "PCF8584 ISA adapter", ++ .id = I2C_HW_P_ELEK, ++ .algo_data = &pcf_isa_data, + }; + +-int __init i2c_pcfisa_init(void) ++static int __init i2c_pcfisa_init(void) + { + #ifdef __alpha__ + /* check to see we have memory mapped PCF8584 connected to the +@@ -277,22 +245,41 @@ + } + + init_waitqueue_head(&pcf_wait); +- if (pcf_isa_init() == 0) { +- if (i2c_pcf_add_bus(&pcf_isa_ops) < 0) +- return -ENODEV; +- } else { ++ if (pcf_isa_init()) + return -ENODEV; +- } ++ if (i2c_pcf_add_bus(&pcf_isa_ops) < 0) ++ goto fail; + + printk(KERN_DEBUG "i2c-elektor.o: found device at %#x.\n", base); + + return 0; ++ ++ fail: ++ if (irq > 0) { ++ disable_irq(irq); ++ free_irq(irq, 0); ++ } ++ ++ if (!mmapped) ++ release_region(base , 2); ++ return -ENODEV; + } + ++static void __exit i2c_pcfisa_exit(void) ++{ ++ i2c_pcf_del_bus(&pcf_isa_ops); ++ ++ if (irq > 0) { ++ disable_irq(irq); ++ free_irq(irq, 0); ++ } ++ ++ if (!mmapped) ++ release_region(base , 2); ++} + + EXPORT_NO_SYMBOLS; + +-#ifdef MODULE + MODULE_AUTHOR("Hans Berglund <hb@spacetec.no>"); + MODULE_DESCRIPTION("I2C-Bus adapter routines for PCF8584 ISA bus adapter"); + MODULE_LICENSE("GPL"); +@@ -304,15 +291,5 @@ + MODULE_PARM(mmapped, "i"); + MODULE_PARM(i2c_debug, "i"); + +-int init_module(void) +-{ +- return i2c_pcfisa_init(); +-} +- +-void cleanup_module(void) +-{ +- i2c_pcf_del_bus(&pcf_isa_ops); +- pcf_isa_exit(); +-} +- +-#endif ++module_init(i2c_pcfisa_init); ++module_exit(i2c_pcfisa_exit); +--- linux-old/include/linux/i2c-elektor.h Tue Nov 6 00:55:29 2001 ++++ linux/include/linux/i2c-elektor.h Mon Dec 13 19:26:33 2004 +@@ -1,47 +0,0 @@ +-/* ------------------------------------------------------------------------- */ +-/* i2c-elektor.c i2c-hw access for PCF8584 style isa bus adaptes */ +-/* ------------------------------------------------------------------------- */ +-/* 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> */ +- +-/* $Id: i2c-elektor.h,v 1.5 2001/06/05 01:46:33 mds Exp $ */ +- +-#ifndef I2C_PCF_ELEKTOR_H +-#define I2C_PCF_ELEKTOR_H 1 +- +-/* +- * This struct contains the hw-dependent functions of PCF8584 adapters to +- * manipulate the registers, and to init any hw-specific features. +- * vdovikin: removed: this module in real supports only one device, +- * due to missing arguments in some functions, called from the algo-pcf module. +- * Sometimes it's need to be rewriten - +- * but for now just remove this for simpler reading */ +- +-/* +-struct i2c_pcf_isa { +- int pi_base; +- int pi_irq; +- int pi_clock; +- int pi_own; +-}; +-*/ +- +-#endif /* PCF_ELEKTOR_H */ +--- linux-old/drivers/i2c/i2c-elv.c Tue Jan 20 15:10:31 2004 ++++ linux/drivers/i2c/i2c-elv.c Mon Dec 13 19:26:33 2004 +@@ -21,21 +21,18 @@ + /* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even + Frodo Looijaard <frodol@dds.nl> */ + +-/* $Id: i2c-elv.c,v 1.17 2001/07/29 02:44:25 mds Exp $ */ ++/* $Id: i2c-elv.c,v 1.29 2003/12/22 20:03:11 khali Exp $ */ + + #include <linux/kernel.h> + #include <linux/module.h> + #include <linux/delay.h> + #include <linux/slab.h> + #include <linux/init.h> +- +-#include <asm/uaccess.h> +- + #include <linux/ioport.h> +-#include <asm/io.h> + #include <linux/errno.h> + #include <linux/i2c.h> + #include <linux/i2c-algo-bit.h> ++#include <asm/io.h> + + #define DEFAULT_BASE 0x378 + static int base=0; +@@ -89,58 +86,31 @@ + + static int bit_elv_init(void) + { +- if (check_region(base,(base == 0x3bc)? 3 : 8) < 0 ) { +- return -ENODEV; +- } else { +- /* test for ELV adap. */ +- if (inb(base+1) & 0x80) { /* BUSY should be high */ +- DEBINIT(printk(KERN_DEBUG "i2c-elv.o: Busy was low.\n")); +- return -ENODEV; +- } else { +- outb(0x0c,base+2); /* SLCT auf low */ +- udelay(400); +- if ( !(inb(base+1) && 0x10) ) { +- outb(0x04,base+2); +- DEBINIT(printk(KERN_DEBUG "i2c-elv.o: Select was high.\n")); +- return -ENODEV; +- } +- } +- request_region(base,(base == 0x3bc)? 3 : 8, +- "i2c (ELV adapter)"); +- PortData = 0; +- bit_elv_setsda((void*)base,1); +- bit_elv_setscl((void*)base,1); ++ if (!request_region(base, (base == 0x3bc) ? 3 : 8, ++ "i2c (ELV adapter)")) ++ return -ENODEV; ++ ++ if (inb(base+1) & 0x80) { /* BUSY should be high */ ++ DEBINIT(printk(KERN_DEBUG "i2c-elv.o: Busy was low.\n")); ++ goto fail; ++ } ++ ++ outb(0x0c,base+2); /* SLCT auf low */ ++ udelay(400); ++ if (!(inb(base+1) && 0x10)) { ++ outb(0x04,base+2); ++ DEBINIT(printk(KERN_DEBUG "i2c-elv.o: Select was high.\n")); ++ goto fail; + } +- return 0; +-} +- +-static void __exit bit_elv_exit(void) +-{ +- release_region( base , (base == 0x3bc)? 3 : 8 ); +-} +- +-static int bit_elv_reg(struct i2c_client *client) +-{ +- return 0; +-} + +-static int bit_elv_unreg(struct i2c_client *client) +-{ ++ PortData = 0; ++ bit_elv_setsda((void*)base,1); ++ bit_elv_setscl((void*)base,1); + return 0; +-} + +-static void bit_elv_inc_use(struct i2c_adapter *adap) +-{ +-#ifdef MODULE +- MOD_INC_USE_COUNT; +-#endif +-} +- +-static void bit_elv_dec_use(struct i2c_adapter *adap) +-{ +-#ifdef MODULE +- MOD_DEC_USE_COUNT; +-#endif ++fail: ++ release_region(base , (base == 0x3bc) ? 3 : 8); ++ return -ENODEV; + } + + /* ------------------------------------------------------------------------ +@@ -148,26 +118,23 @@ + * This is only done when more than one hardware adapter is supported. + */ + static struct i2c_algo_bit_data bit_elv_data = { +- NULL, +- bit_elv_setsda, +- bit_elv_setscl, +- bit_elv_getsda, +- bit_elv_getscl, +- 80, 80, 100, /* waits, timeout */ ++ .setsda = bit_elv_setsda, ++ .setscl = bit_elv_setscl, ++ .getsda = bit_elv_getsda, ++ .getscl = bit_elv_getscl, ++ .udelay = 80, ++ .mdelay = 80, ++ .timeout = HZ + }; + + static struct i2c_adapter bit_elv_ops = { +- "ELV Parallel port adaptor", +- I2C_HW_B_ELV, +- NULL, +- &bit_elv_data, +- bit_elv_inc_use, +- bit_elv_dec_use, +- bit_elv_reg, +- bit_elv_unreg, ++ .owner = THIS_MODULE, ++ .name = "ELV Parallel port adaptor", ++ .id = I2C_HW_B_ELV, ++ .algo_data = &bit_elv_data, + }; + +-int __init i2c_bitelv_init(void) ++static int __init i2c_bitelv_init(void) + { + printk(KERN_INFO "i2c-elv.o: i2c ELV parallel port adapter module version %s (%s)\n", I2C_VERSION, I2C_DATE); + if (base==0) { +@@ -193,25 +160,19 @@ + return 0; + } + ++static void __exit i2c_bitelv_exit(void) ++{ ++ i2c_bit_del_bus(&bit_elv_ops); ++ release_region(base, (base == 0x3bc) ? 3 : 8); ++} + + EXPORT_NO_SYMBOLS; + +-#ifdef MODULE + MODULE_AUTHOR("Simon G. Vogl <simon@tk.uni-linz.ac.at>"); + MODULE_DESCRIPTION("I2C-Bus adapter routines for ELV parallel port adapter"); + MODULE_LICENSE("GPL"); + + MODULE_PARM(base, "i"); + +-int init_module(void) +-{ +- return i2c_bitelv_init(); +-} +- +-void cleanup_module(void) +-{ +- i2c_bit_del_bus(&bit_elv_ops); +- bit_elv_exit(); +-} +- +-#endif ++module_init(i2c_bitelv_init); ++module_exit(i2c_bitelv_exit); +--- linux-old/drivers/i2c/i2c-frodo.c Thu Jan 1 00:00:00 1970 ++++ linux/drivers/i2c/i2c-frodo.c Mon Dec 13 19:26:33 2004 +@@ -0,0 +1,83 @@ ++ ++/* ++ * 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, ++ .name = "Frodo adapter driver", ++ .id = I2C_HW_B_FRODO, ++ .algo_data = &bit_frodo_data, ++}; ++ ++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); ++ +--- linux-old/include/linux/i2c-id.h Wed Jul 7 00:38:02 2004 ++++ linux/include/linux/i2c-id.h Mon Dec 13 19:26:33 2004 +@@ -20,10 +20,11 @@ + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + /* ------------------------------------------------------------------------- */ + +-/* $Id: i2c-id.h,v 1.35 2001/08/12 17:22:20 mds Exp $ */ ++/* $Id: i2c-id.h,v 1.92 2004/07/27 18:15:06 mmh Exp $ */ ++ ++#ifndef LINUX_I2C_ID_H ++#define LINUX_I2C_ID_H + +-#ifndef I2C_ID_H +-#define I2C_ID_H + /* + * This file is part of the i2c-bus package and contains the identifier + * values for drivers, adapters and other folk populating these serial +@@ -90,10 +91,25 @@ + #define I2C_DRIVERID_DRP3510 43 /* ADR decoder (Astra Radio) */ + #define I2C_DRIVERID_SP5055 44 /* Satellite tuner */ + #define I2C_DRIVERID_STV0030 45 /* Multipurpose switch */ ++#define I2C_DRIVERID_SAA7108 46 /* video decoder, image scaler */ ++#define I2C_DRIVERID_DS1307 47 /* DS1307 real time clock */ + #define I2C_DRIVERID_ADV7175 48 /* ADV 7175/7176 video encoder */ +-#define I2C_DRIVERID_MAX1617 56 /* temp sensor */ +-#define I2C_DRIVERID_SAA7191 57 /* video decoder */ +-#define I2C_DRIVERID_INDYCAM 58 /* SGI IndyCam */ ++#define I2C_DRIVERID_ZR36067 49 /* Zoran 36067 video encoder */ ++#define I2C_DRIVERID_ZR36120 50 /* Zoran 36120 video encoder */ ++#define I2C_DRIVERID_24LC32A 51 /* Microchip 24LC32A 32k EEPROM */ ++#define I2C_DRIVERID_STM41T00 52 /* real time clock */ ++#define I2C_DRIVERID_UDA1342 53 /* UDA1342 audio codec */ ++#define I2C_DRIVERID_ADV7170 54 /* video encoder */ ++#define I2C_DRIVERID_RADEON 55 /* I2C bus on Radeon boards */ ++#define I2C_DRIVERID_MAX1617 56 /* temp sensor */ ++#define I2C_DRIVERID_SAA7191 57 /* video encoder */ ++#define I2C_DRIVERID_INDYCAM 58 /* SGI IndyCam */ ++#define I2C_DRIVERID_BT832 59 /* CMOS camera video processor */ ++#define I2C_DRIVERID_TDA9887 60 /* TDA988x IF-PLL demodulator */ ++#define I2C_DRIVERID_OVCAMCHIP 61 /* OmniVision CMOS image sens. */ ++#define I2C_DRIVERID_TDA7313 62 /* TDA7313 audio processor */ ++#define I2C_DRIVERID_MAX6900 63 /* MAX6900 real-time clock */ ++ + + #define I2C_DRIVERID_EXP0 0xF0 /* experimental use id's */ + #define I2C_DRIVERID_EXP1 0xF1 +@@ -102,6 +118,8 @@ + + #define I2C_DRIVERID_I2CDEV 900 + #define I2C_DRIVERID_I2CPROC 901 ++#define I2C_DRIVERID_ARP 902 /* SMBus ARP Client */ ++#define I2C_DRIVERID_ALERT 903 /* SMBus Alert Responder Client */ + + /* IDs -- Use DRIVERIDs 1000-1999 for sensors. + These were originally in sensors.h in the lm_sensors package */ +@@ -131,6 +149,28 @@ + #define I2C_DRIVERID_ADM1024 1025 + #define I2C_DRIVERID_IT87 1026 + #define I2C_DRIVERID_CH700X 1027 /* single driver for CH7003-7009 digital pc to tv encoders */ ++#define I2C_DRIVERID_FSCPOS 1028 ++#define I2C_DRIVERID_FSCSCY 1029 ++#define I2C_DRIVERID_PCF8591 1030 ++#define I2C_DRIVERID_SMSC47M1 1031 ++#define I2C_DRIVERID_VT1211 1032 ++#define I2C_DRIVERID_LM92 1033 ++#define I2C_DRIVERID_VT8231 1034 ++#define I2C_DRIVERID_SMARTBATT 1035 ++#define I2C_DRIVERID_BMCSENSORS 1036 ++#define I2C_DRIVERID_FS451 1037 ++#define I2C_DRIVERID_W83627HF 1038 ++#define I2C_DRIVERID_LM85 1039 ++#define I2C_DRIVERID_LM83 1040 ++#define I2C_DRIVERID_SAA1064 1041 ++#define I2C_DRIVERID_LM90 1042 ++#define I2C_DRIVERID_ASB100 1043 ++#define I2C_DRIVERID_MAX6650 1044 ++#define I2C_DRIVERID_XEONTEMP 1045 ++#define I2C_DRIVERID_FSCHER 1046 ++#define I2C_DRIVERID_W83L785TS 1047 ++#define I2C_DRIVERID_ADM1026 1048 ++#define I2C_DRIVERID_LM93 1049 + + /* + * ---- Adapter types ---------------------------------------------------- +@@ -147,16 +187,21 @@ + #define I2C_ALGO_ISA 0x050000 /* lm_sensors ISA pseudo-adapter */ + #define I2C_ALGO_SAA7146 0x060000 /* SAA 7146 video decoder bus */ + #define I2C_ALGO_ACB 0x070000 /* ACCESS.bus algorithm */ +- ++#define I2C_ALGO_IIC 0x080000 /* ITE IIC bus */ ++#define I2C_ALGO_SAA7134 0x090000 ++#define I2C_ALGO_MPC824X 0x0a0000 /* Motorola 8240 / 8245 */ ++#define I2C_ALGO_IPMI 0x0b0000 /* IPMI dummy adapter */ ++#define I2C_ALGO_IPMB 0x0c0000 /* IPMB adapter */ ++#define I2C_ALGO_MPC107 0x0d0000 + #define I2C_ALGO_EC 0x100000 /* ACPI embedded controller */ + + #define I2C_ALGO_MPC8XX 0x110000 /* MPC8xx PowerPC I2C algorithm */ +- +-#define I2C_ALGO_SIBYTE 0x120000 /* Broadcom SiByte SOCs */ +- +-#define I2C_ALGO_SGI 0x130000 /* SGI algorithm */ +- +-#define I2C_ALGO_AU1550 0x140000 /* Alchemy Au1550 PSC */ ++#define I2C_ALGO_OCP 0x120000 /* IBM or otherwise On-chip I2C algorithm */ ++#define I2C_ALGO_BITHS 0x130000 /* enhanced bit style adapters */ ++#define I2C_ALGO_OCP_IOP3XX 0x140000 /* XSCALE IOP3XX On-chip I2C alg */ ++#define I2C_ALGO_SIBYTE 0x150000 /* Broadcom SiByte SOCs */ ++#define I2C_ALGO_SGI 0x160000 /* SGI algorithm */ ++#define I2C_ALGO_USB 0x170000 /* USB algorithm */ + + #define I2C_ALGO_EXP 0x800000 /* experimental */ + +@@ -184,21 +229,46 @@ + #define I2C_HW_B_I810 0x0a /* Intel I810 */ + #define I2C_HW_B_VOO 0x0b /* 3dfx Voodoo 3 / Banshee */ + #define I2C_HW_B_PPORT 0x0c /* Primitive parallel port adapter */ ++#define I2C_HW_B_SAVG 0x0d /* Savage 4 */ ++#define I2C_HW_B_SCX200 0x0e /* Nat'l Semi SCx200 I2C */ + #define I2C_HW_B_RIVA 0x10 /* Riva based graphics cards */ + #define I2C_HW_B_IOC 0x11 /* IOC bit-wiggling */ + #define I2C_HW_B_TSUNA 0x12 /* DEC Tsunami chipset */ ++#define I2C_HW_B_FRODO 0x13 /* 2d3D, Inc. SA-1110 Development Board */ ++#define I2C_HW_B_OMAHA 0x14 /* Omaha I2C interface (ARM) */ ++#define I2C_HW_B_GUIDE 0x15 /* Guide bit-basher */ ++#define I2C_HW_B_IXP2000 0x16 /* GPIO on IXP2000 systems */ ++#define I2C_HW_B_IXP425 0x17 /* GPIO on IXP425 systems */ ++#define I2C_HW_B_S3VIA 0x18 /* S3Via ProSavage adapter */ ++#define I2C_HW_B_ZR36067 0x19 /* Zoran-36057/36067 based boards */ ++#define I2C_HW_B_PCILYNX 0x1a /* TI PCILynx I2C adapter */ + + /* --- PCF 8584 based algorithms */ + #define I2C_HW_P_LP 0x00 /* Parallel port interface */ + #define I2C_HW_P_ISA 0x01 /* generic ISA Bus inteface card */ + #define I2C_HW_P_ELEK 0x02 /* Elektor ISA Bus inteface card */ + ++/* --- USB based adapters */ ++#define I2C_HW_USB_USBVISION 0x00 ++ + /* --- ACPI Embedded controller algorithms */ + #define I2C_HW_ACPI_EC 0x00 + ++/* --- MPC824x PowerPC adapters */ ++#define I2C_HW_MPC824X 0x00 /* Motorola 8240 / 8245 */ ++ + /* --- MPC8xx PowerPC adapters */ + #define I2C_HW_MPC8XX_EPON 0x00 /* Eponymous MPC8xx I2C adapter */ + ++/* --- ITE based algorithms */ ++#define I2C_HW_I_IIC 0x00 /* controller on the ITE */ ++ ++/* --- PowerPC on-chip adapters */ ++#define I2C_HW_OCP 0x00 /* IBM on-chip I2C adapter */ ++ ++/* --- XSCALE on-chip adapters */ ++#define I2C_HW_IOP321 0x00 ++ + /* --- Broadcom SiByte adapters */ + #define I2C_HW_SIBYTE 0x00 + +@@ -206,9 +276,6 @@ + #define I2C_HW_SGI_VINO 0x00 + #define I2C_HW_SGI_MACE 0x01 + +-/* --- Au1550 PSC adapters */ +-#define I2C_HW_AU1550_PSC 0x00 +- + /* --- SMBus only adapters */ + #define I2C_HW_SMBUS_PIIX4 0x00 + #define I2C_HW_SMBUS_ALI15X3 0x01 +@@ -218,9 +285,27 @@ + #define I2C_HW_SMBUS_AMD756 0x05 + #define I2C_HW_SMBUS_SIS5595 0x06 + #define I2C_HW_SMBUS_ALI1535 0x07 ++#define I2C_HW_SMBUS_SIS630 0x08 ++#define I2C_HW_SMBUS_SIS645 0x09 ++#define I2C_HW_SMBUS_AMD8111 0x0a ++#define I2C_HW_SMBUS_SCX200 0x0b ++#define I2C_HW_SMBUS_NFORCE2 0x0c + #define I2C_HW_SMBUS_W9968CF 0x0d ++#define I2C_HW_SMBUS_OV511 0x0e /* OV511(+) USB 1.1 webcam ICs */ ++#define I2C_HW_SMBUS_OV518 0x0f /* OV518(+) USB 1.1 webcam ICs */ ++#define I2C_HW_SMBUS_OV519 0x10 /* OV519 USB 1.1 webcam IC */ ++#define I2C_HW_SMBUS_OVFX2 0x11 /* Cypress/OmniVision FX2 webcam */ + + /* --- ISA pseudo-adapter */ + #define I2C_HW_ISA 0x00 + +-#endif /* I2C_ID_H */ ++/* --- IPMI pseudo-adapter */ ++#define I2C_HW_IPMI 0x00 ++ ++/* --- IPMB adapter */ ++#define I2C_HW_IPMB 0x00 ++ ++/* --- MCP107 adapter */ ++#define I2C_HW_MPC107 0x00 ++ ++#endif /* LINUX_I2C_ID_H */ +--- linux-old/drivers/i2c/i2c-pcf-epp.c Thu Jan 1 00:00:00 1970 ++++ linux/drivers/i2c/i2c-pcf-epp.c Mon Dec 13 19:26:34 2004 +@@ -0,0 +1,281 @@ ++/* ------------------------------------------------------------------------- */ ++/* i2c-pcf-epp.c i2c-hw access for PCF8584 style EPP parallel port adapters */ ++/* ------------------------------------------------------------------------- */ ++/* Copyright (C) 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 Ryosuke Tajima <rosk@jsk.t.u-tokyo.ac.jp> */ ++ ++#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 <linux/parport.h> ++#include <linux/i2c.h> ++#include <linux/i2c-algo-pcf.h> ++#include <asm/irq.h> ++#include <asm/io.h> ++ ++ ++struct i2c_pcf_epp { ++ int pe_base; ++ int pe_irq; ++ int pe_clock; ++ int pe_own; ++} ; ++ ++#define DEFAULT_BASE 0x378 ++#define DEFAULT_IRQ 7 ++#define DEFAULT_CLOCK 0x1c ++#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 i2c_pcf_epp gpe; ++static wait_queue_head_t pcf_wait; ++static int pcf_pending; ++static spinlock_t irq_driver_lock = SPIN_LOCK_UNLOCKED; ++ ++/* ----- 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 */ ++ ++/* --- Convenience defines for the EPP/SPP port: */ ++#define BASE ((struct i2c_pcf_epp *)(data))->pe_base ++// #define DATA BASE /* SPP data port */ ++#define STAT (BASE+1) /* SPP status port */ ++#define CTRL (BASE+2) /* SPP control port */ ++#define EADD (BASE+3) /* EPP address port */ ++#define EDAT (BASE+4) /* EPP data port */ ++ ++/* ----- local functions ---------------------------------------------- */ ++ ++static void pcf_epp_setbyte(void *data, int ctl, int val) ++{ ++ if (ctl) { ++ if (gpe.pe_irq > 0) { ++ DEB3(printk(KERN_DEBUG "i2c-pcf-epp.o: Write control 0x%x\n", ++ val|I2C_PCF_ENI)); ++ // set A0 pin HIGH ++ outb(inb(CTRL) | PARPORT_CONTROL_INIT, CTRL); ++ // DEB3(printk(KERN_DEBUG "i2c-pcf-epp.o: CTRL port = 0x%x\n", inb(CTRL))); ++ // DEB3(printk(KERN_DEBUG "i2c-pcf-epp.o: STAT port = 0x%x\n", inb(STAT))); ++ ++ // EPP write data cycle ++ outb(val | I2C_PCF_ENI, EDAT); ++ } else { ++ DEB3(printk(KERN_DEBUG "i2c-pcf-epp.o: Write control 0x%x\n", val)); ++ // set A0 pin HIGH ++ outb(inb(CTRL) | PARPORT_CONTROL_INIT, CTRL); ++ outb(val, CTRL); ++ } ++ } else { ++ DEB3(printk(KERN_DEBUG "i2c-pcf-epp.o: Write data 0x%x\n", val)); ++ // set A0 pin LO ++ outb(inb(CTRL) & ~PARPORT_CONTROL_INIT, CTRL); ++ // DEB3(printk(KERN_DEBUG "i2c-pcf-epp.o: CTRL port = 0x%x\n", inb(CTRL))); ++ // DEB3(printk(KERN_DEBUG "i2c-pcf-epp.o: STAT port = 0x%x\n", inb(STAT))); ++ outb(val, EDAT); ++ } ++} ++ ++static int pcf_epp_getbyte(void *data, int ctl) ++{ ++ int val; ++ ++ if (ctl) { ++ // set A0 pin HIGH ++ outb(inb(CTRL) | PARPORT_CONTROL_INIT, CTRL); ++ val = inb(EDAT); ++ DEB3(printk(KERN_DEBUG "i2c-pcf-epp.o: Read control 0x%x\n", val)); ++ } else { ++ // set A0 pin LOW ++ outb(inb(CTRL) & ~PARPORT_CONTROL_INIT, CTRL); ++ val = inb(EDAT); ++ DEB3(printk(KERN_DEBUG "i2c-pcf-epp.o: Read data 0x%x\n", val)); ++ } ++ return (val); ++} ++ ++static int pcf_epp_getown(void *data) ++{ ++ return (gpe.pe_own); ++} ++ ++ ++static int pcf_epp_getclock(void *data) ++{ ++ return (gpe.pe_clock); ++} ++ ++#if 0 ++static void pcf_epp_sleep(unsigned long timeout) ++{ ++ schedule_timeout( timeout * HZ); ++} ++#endif ++ ++static void pcf_epp_waitforpin(void) { ++ int timeout = 10; ++ ++ if (gpe.pe_irq > 0) { ++ spin_lock_irq(&irq_driver_lock); ++ if (pcf_pending == 0) { ++ interruptible_sleep_on_timeout(&pcf_wait, timeout*HZ); ++ //udelay(100); ++ } else { ++ pcf_pending = 0; ++ } ++ spin_unlock_irq(&irq_driver_lock); ++ } else { ++ udelay(100); ++ } ++} ++ ++static void pcf_epp_handler(int this_irq, void *dev_id, struct pt_regs *regs) { ++ pcf_pending = 1; ++ wake_up_interruptible(&pcf_wait); ++ DEB3(printk(KERN_DEBUG "i2c-pcf-epp.o: in interrupt handler.\n")); ++} ++ ++ ++static int pcf_epp_init(void *data) ++{ ++ if (check_region(gpe.pe_base, 5) < 0 ) { ++ ++ printk(KERN_WARNING "Could not request port region with base 0x%x\n", gpe.pe_base); ++ return -ENODEV; ++ } else { ++ request_region(gpe.pe_base, 5, "i2c (EPP parallel port adapter)"); ++ } ++ ++ DEB3(printk(KERN_DEBUG "i2c-pcf-epp.o: init status port = 0x%x\n", inb(0x379))); ++ ++ if (gpe.pe_irq > 0) { ++ if (request_irq(gpe.pe_irq, pcf_epp_handler, 0, "PCF8584", 0) < 0) { ++ printk(KERN_NOTICE "i2c-pcf-epp.o: Request irq%d failed\n", gpe.pe_irq); ++ gpe.pe_irq = 0; ++ } else ++ disable_irq(gpe.pe_irq); ++ enable_irq(gpe.pe_irq); ++ } ++ // EPP mode initialize ++ // enable interrupt from nINTR pin ++ outb(inb(CTRL)|0x14, CTRL); ++ // clear ERROR bit of STAT ++ outb(inb(STAT)|0x01, STAT); ++ outb(inb(STAT)&~0x01,STAT); ++ ++ return 0; ++} ++ ++/* ------------------------------------------------------------------------ ++ * 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_pcf_data pcf_epp_data = { ++ .setpcf = pcf_epp_setbyte, ++ .getpcf = pcf_epp_getbyte, ++ .getown = pcf_epp_getown, ++ .getclock = pcf_epp_getclock, ++ .waitforpin = pcf_epp_waitforpin, ++ .udelay = 80, ++ .mdelay = 80, ++ .timeout = HZ, ++}; ++ ++static struct i2c_adapter pcf_epp_ops = { ++ .owner = THIS_MODULE, ++ .name = "PCF8584 EPP adapter", ++ .id = I2C_HW_P_LP, ++ .algo_data = &pcf_epp_data, ++}; ++ ++static int __init i2c_pcfepp_init(void) ++{ ++ struct i2c_pcf_epp *pepp = &gpe; ++ ++ printk(KERN_DEBUG "i2c-pcf-epp.o: i2c pcf8584-epp adapter module version %s (%s)\n", I2C_VERSION, I2C_DATE); ++ if (base == 0) ++ pepp->pe_base = DEFAULT_BASE; ++ else ++ pepp->pe_base = base; ++ ++ if (irq == 0) ++ pepp->pe_irq = DEFAULT_IRQ; ++ else if (irq<0) { ++ // switch off irq ++ pepp->pe_irq=0; ++ } else { ++ pepp->pe_irq = irq; ++ } ++ if (clock == 0) ++ pepp->pe_clock = DEFAULT_CLOCK; ++ else ++ pepp->pe_clock = clock; ++ ++ if (own == 0) ++ pepp->pe_own = DEFAULT_OWN; ++ else ++ pepp->pe_own = own; ++ ++ pcf_epp_data.data = (void *)pepp; ++ init_waitqueue_head(&pcf_wait); ++ if (pcf_epp_init(pepp) == 0) { ++ int ret; ++ if ( (ret = i2c_pcf_add_bus(&pcf_epp_ops)) < 0) { ++ printk(KERN_WARNING "i2c_pcf_add_bus caused an error: %d\n",ret); ++ release_region(pepp->pe_base , 5); ++ return ret; ++ } ++ } else { ++ ++ return -ENODEV; ++ } ++ printk(KERN_DEBUG "i2c-pcf-epp.o: found device at %#x.\n", pepp->pe_base); ++ return 0; ++} ++ ++static void __exit pcf_epp_exit(void) ++{ ++ i2c_pcf_del_bus(&pcf_epp_ops); ++ if (gpe.pe_irq > 0) { ++ disable_irq(gpe.pe_irq); ++ free_irq(gpe.pe_irq, 0); ++ } ++ release_region(gpe.pe_base , 5); ++} ++ ++MODULE_AUTHOR("Hans Berglund <hb@spacetec.no> \n modified by Ryosuke Tajima <rosk@jsk.t.u-tokyo.ac.jp>"); ++MODULE_DESCRIPTION("I2C-Bus adapter routines for PCF8584 EPP parallel port 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"); ++ ++module_init(i2c_pcfepp_init); ++module_exit(pcf_epp_exit); +--- linux-old/include/linux/i2c-pcf8584.h Thu Jan 1 00:00:00 1970 ++++ linux/include/linux/i2c-pcf8584.h Mon Dec 13 19:26:34 2004 +@@ -0,0 +1,78 @@ ++/* -------------------------------------------------------------------- */ ++/* i2c-pcf8584.h: PCF 8584 global defines */ ++/* -------------------------------------------------------------------- */ ++/* Copyright (C) 1996 Simon G. Vogl ++ 1999 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 Frodo Looijaard <frodol@dds.nl> */ ++ ++/* $Id: i2c-pcf8584.h,v 1.6 2003/07/25 07:56:42 khali Exp $ */ ++ ++#ifndef _LINUX_I2C_PCF8584_H ++#define _LINUX_I2C_PCF8584_H ++ ++/* ----- Control register bits ---------------------------------------- */ ++#define I2C_PCF_PIN 0x80 ++#define I2C_PCF_ESO 0x40 ++#define I2C_PCF_ES1 0x20 ++#define I2C_PCF_ES2 0x10 ++#define I2C_PCF_ENI 0x08 ++#define I2C_PCF_STA 0x04 ++#define I2C_PCF_STO 0x02 ++#define I2C_PCF_ACK 0x01 ++ ++#define I2C_PCF_START (I2C_PCF_PIN | I2C_PCF_ESO | I2C_PCF_STA | I2C_PCF_ACK) ++#define I2C_PCF_STOP (I2C_PCF_PIN | I2C_PCF_ESO | I2C_PCF_STO | I2C_PCF_ACK) ++#define I2C_PCF_REPSTART ( I2C_PCF_ESO | I2C_PCF_STA | I2C_PCF_ACK) ++#define I2C_PCF_IDLE (I2C_PCF_PIN | I2C_PCF_ESO | I2C_PCF_ACK) ++ ++/* ----- Status register bits ----------------------------------------- */ ++/*#define I2C_PCF_PIN 0x80 as above*/ ++ ++#define I2C_PCF_INI 0x40 /* 1 if not initialized */ ++#define I2C_PCF_STS 0x20 ++#define I2C_PCF_BER 0x10 ++#define I2C_PCF_AD0 0x08 ++#define I2C_PCF_LRB 0x08 ++#define I2C_PCF_AAS 0x04 ++#define I2C_PCF_LAB 0x02 ++#define I2C_PCF_BB 0x01 ++ ++/* ----- Chip clock frequencies --------------------------------------- */ ++#define I2C_PCF_CLK3 0x00 ++#define I2C_PCF_CLK443 0x10 ++#define I2C_PCF_CLK6 0x14 ++#define I2C_PCF_CLK 0x18 ++#define I2C_PCF_CLK12 0x1c ++ ++/* ----- transmission frequencies ------------------------------------- */ ++#define I2C_PCF_TRNS90 0x00 /* 90 kHz */ ++#define I2C_PCF_TRNS45 0x01 /* 45 kHz */ ++#define I2C_PCF_TRNS11 0x02 /* 11 kHz */ ++#define I2C_PCF_TRNS15 0x03 /* 1.5 kHz */ ++ ++ ++/* ----- Access to internal registers according to ES1,ES2 ------------ */ ++/* they are mapped to the data port ( a0 = 0 ) */ ++/* available when ESO == 0 : */ ++ ++#define I2C_PCF_OWNADR 0 ++#define I2C_PCF_INTREG I2C_PCF_ES2 ++#define I2C_PCF_CLKREG I2C_PCF_ES1 ++ ++#endif /* _LINUX_I2C_PCF8584_H */ +--- linux-old/drivers/i2c/i2c-philips-par.c Fri Feb 20 01:22:16 2004 ++++ linux/drivers/i2c/i2c-philips-par.c Mon Dec 13 19:26:34 2004 +@@ -21,7 +21,7 @@ + /* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even + Frodo Looijaard <frodol@dds.nl> */ + +-/* $Id: i2c-philips-par.c,v 1.18 2000/07/06 19:21:49 frodo Exp $ */ ++/* $Id: i2c-philips-par.c,v 1.33 2004/01/23 20:22:53 khali Exp $ */ + + #include <linux/kernel.h> + #include <linux/ioport.h> +@@ -29,14 +29,10 @@ + #include <linux/init.h> + #include <linux/stddef.h> + #include <linux/parport.h> +- ++#include <linux/slab.h> + #include <linux/i2c.h> + #include <linux/i2c-algo-bit.h> + +-#ifndef __exit +-#define __exit __init +-#endif +- + static int type; + + struct i2c_par +@@ -130,59 +126,34 @@ + PARPORT_STATUS_BUSY) ? 0 : 1; + } + +-static int bit_lp_reg(struct i2c_client *client) +-{ +- return 0; +-} +- +-static int bit_lp_unreg(struct i2c_client *client) +-{ +- return 0; +-} +- +-static void bit_lp_inc_use(struct i2c_adapter *adap) +-{ +- MOD_INC_USE_COUNT; +-} +- +-static void bit_lp_dec_use(struct i2c_adapter *adap) +-{ +- MOD_DEC_USE_COUNT; +-} +- + /* ------------------------------------------------------------------------ + * 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_bit_data bit_lp_data = { +- NULL, +- bit_lp_setsda, +- bit_lp_setscl, +- bit_lp_getsda, +- bit_lp_getscl, +- 80, 80, 100, /* waits, timeout */ ++ .setsda = bit_lp_setsda, ++ .setscl = bit_lp_setscl, ++ .getsda = bit_lp_getsda, ++ .getscl = bit_lp_getscl, ++ .udelay = 80, ++ .mdelay = 80, ++ .timeout = HZ + }; + + static struct i2c_algo_bit_data bit_lp_data2 = { +- NULL, +- bit_lp_setsda2, +- bit_lp_setscl2, +- bit_lp_getsda2, +- NULL, +- 80, 80, 100, /* waits, timeout */ ++ .setsda = bit_lp_setsda2, ++ .setscl = bit_lp_setscl2, ++ .getsda = bit_lp_getsda2, ++ .udelay = 80, ++ .mdelay = 80, ++ .timeout = HZ + }; + + static struct i2c_adapter bit_lp_ops = { +- "Philips Parallel port adapter", +- I2C_HW_B_LP, +- NULL, +- NULL, +- bit_lp_inc_use, +- bit_lp_dec_use, +- bit_lp_reg, +- +- bit_lp_unreg, ++ .owner = THIS_MODULE, ++ .name = "Philips Parallel port adapter", ++ .id = I2C_HW_B_LP, + }; + + static void i2c_parport_attach (struct parport *port) +@@ -202,6 +173,7 @@ + NULL); + if (!adapter->pdev) { + printk(KERN_ERR "i2c-philips-par: Unable to register with parport.\n"); ++ kfree(adapter); + return; + } + +@@ -210,8 +182,12 @@ + adapter->bit_lp_data = type ? bit_lp_data2 : bit_lp_data; + adapter->bit_lp_data.data = port; + ++ if (parport_claim_or_block(adapter->pdev) < 0 ) { ++ printk(KERN_ERR "i2c-philips-par: Could not claim parallel port.\n"); ++ kfree(adapter); ++ return; ++ } + /* reset hardware to sane state */ +- parport_claim_or_block(adapter->pdev); + adapter->bit_lp_data.setsda(port, 1); + adapter->bit_lp_data.setscl(port, 1); + parport_release(adapter->pdev); +@@ -257,7 +233,7 @@ + NULL + }; + +-int __init i2c_bitlp_init(void) ++static int __init i2c_bitlp_init(void) + { + printk(KERN_INFO "i2c-philips-par.o: i2c Philips parallel port adapter module version %s (%s)\n", I2C_VERSION, I2C_DATE); + +@@ -266,7 +242,7 @@ + return 0; + } + +-void __exit i2c_bitlp_exit(void) ++static void __exit i2c_bitlp_exit(void) + { + parport_unregister_driver(&i2c_driver); + } +@@ -279,14 +255,5 @@ + + MODULE_PARM(type, "i"); + +-#ifdef MODULE +-int init_module(void) +-{ +- return i2c_bitlp_init(); +-} +- +-void cleanup_module(void) +-{ +- i2c_bitlp_exit(); +-} +-#endif ++module_init(i2c_bitlp_init); ++module_exit(i2c_bitlp_exit); +--- linux-old/drivers/i2c/i2c-pport.c Thu Jan 1 00:00:00 1970 ++++ linux/drivers/i2c/i2c-pport.c Mon Dec 13 19:26:34 2004 +@@ -0,0 +1,169 @@ ++/* ------------------------------------------------------------------------- */ ++/* i2c-pport.c i2c-hw access for primitive i2c par. port adapter */ ++/* ------------------------------------------------------------------------- */ ++/* Copyright (C) 2001 Daniel Smolik ++ ++ 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. */ ++/* ------------------------------------------------------------------------- */ ++ ++/* ++ See doc/i2c-pport for instructions on wiring to the ++ parallel port connector. ++ ++ Cut & paste :-) based on Velleman K8000 driver by Simon G. Vogl ++ ++ Note that SDA is hardware inverted. ++*/ ++ ++ ++#include <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/delay.h> ++#include <linux/slab.h> ++#include <linux/init.h> ++#include <linux/ioport.h> ++#include <linux/errno.h> ++#include <linux/i2c.h> ++#include <linux/i2c-algo-bit.h> ++#include <asm/io.h> ++ ++ ++#define DEFAULT_BASE 0x378 ++static int base = DEFAULT_BASE; ++static unsigned char PortData = 0; ++ ++/* ----- global defines ----------------------------------------------- */ ++#define DEB(x) /* should be reasonable open, close &c. */ ++#define DEB2(x) /* low level debugging - very slow */ ++#define DEBE(x) x /* error messages */ ++#define DEBINIT(x) x /* detection status messages */ ++ ++/* --- Convenience defines for the parallel port: */ ++#define BASE (unsigned int)(data) ++#define DATA BASE /* Centronics data port */ ++#define STAT (BASE+1) /* Centronics status port */ ++#define CTRL (BASE+2) /* Centronics control port */ ++ ++/* we will use SDA - Auto Linefeed(14) POUT (ctrl bit 1) */ ++/* we will use SCL - Initialize printer(16) BUSY (ctrl bit 2) */ ++ ++#define SET_SCL | 0x04 ++#define CLR_SCL & 0xFB ++ ++#define SET_SDA & 0xFD ++#define CLR_SDA | 0x02 ++ ++ ++/* ----- local functions ---------------------------------------------- */ ++ ++ ++static void bit_pport_setscl(void *data, int state) ++{ ++ if (state) { ++ PortData = PortData SET_SCL; ++ } else { ++ PortData = PortData CLR_SCL; ++ } ++ outb(PortData, CTRL); ++} ++ ++static void bit_pport_setsda(void *data, int state) ++{ ++ if (state) { ++ PortData = PortData SET_SDA; ++ } else { ++ PortData = PortData CLR_SDA; ++ } ++ outb(PortData, CTRL); ++} ++ ++static int bit_pport_getscl(void *data) ++{ ++ return ( 4 == ( (inb_p(CTRL)) & 0x04 ) ); ++} ++ ++static int bit_pport_getsda(void *data) ++{ ++ return ( 0 == ( (inb_p(CTRL)) & 0x02 ) ); ++} ++ ++static int bit_pport_init(void) ++{ ++ if (!request_region((base+2),1, "i2c (PPORT adapter)")) { ++ return -ENODEV; ++ } ++ ++ PortData = inb(base+2); ++ bit_pport_setsda((void*)base, 1); ++ bit_pport_setscl((void*)base, 1); ++ ++ return 0; ++} ++ ++ ++/* ------------------------------------------------------------------------ ++ * 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_bit_data bit_pport_data = { ++ .setsda = bit_pport_setsda, ++ .setscl = bit_pport_setscl, ++ .getsda = bit_pport_getsda, ++ .getscl = bit_pport_getscl, ++ .udelay = 40, ++ .mdelay = 80, ++ .timeout = HZ ++}; ++ ++static struct i2c_adapter bit_pport_ops = { ++ .owner = THIS_MODULE, ++ .name = "Primitive Parallel port adaptor", ++ .id = I2C_HW_B_PPORT, ++ .algo_data = &bit_pport_data, ++}; ++ ++static int __init i2c_bitpport_init(void) ++{ ++ printk("i2c-pport.o: i2c Primitive parallel port adapter module version %s (%s)\n", I2C_VERSION, I2C_DATE); ++ ++ bit_pport_data.data = (void*)base; ++ if (bit_pport_init() < 0) ++ return -ENODEV; ++ ++ if (i2c_bit_add_bus(&bit_pport_ops) < 0) { ++ release_region(base+2, 1); ++ return -ENODEV; ++ } ++ ++ printk("i2c-pport.o: found device at %#x.\n",base); ++ return 0; ++} ++ ++static void __exit i2c_bitpport_exit(void) ++{ ++ i2c_bit_del_bus(&bit_pport_ops); ++ release_region((base+2),1); ++} ++ ++EXPORT_NO_SYMBOLS; ++ ++MODULE_AUTHOR("Daniel Smolik <marvin@sitour.cz>"); ++MODULE_DESCRIPTION("I2C-Bus adapter routines for Primitive parallel port adapter"); ++MODULE_LICENSE("GPL"); ++ ++MODULE_PARM(base, "i"); ++ ++module_init(i2c_bitpport_init); ++module_exit(i2c_bitpport_exit); +--- linux-old/drivers/i2c/i2c-proc.c Tue Jan 20 15:10:31 2004 ++++ linux/drivers/i2c/i2c-proc.c Mon Dec 13 19:26:35 2004 +@@ -23,29 +23,26 @@ + This driver puts entries in /proc/sys/dev/sensors for each I2C device + */ + ++#include <linux/config.h> + #include <linux/module.h> + #include <linux/kernel.h> + #include <linux/slab.h> + #include <linux/ctype.h> + #include <linux/sysctl.h> + #include <linux/proc_fs.h> ++#include <linux/init.h> + #include <linux/ioport.h> +-#include <asm/uaccess.h> +- + #include <linux/i2c.h> + #include <linux/i2c-proc.h> ++#include <asm/uaccess.h> + +-#include <linux/init.h> +- +-#ifndef THIS_MODULE +-#define THIS_MODULE NULL ++#ifndef CONFIG_SYSCTL ++#error Your kernel lacks sysctl support (CONFIG_SYSCTL)! + #endif + +-static int i2c_create_name(char **name, const char *prefix, +- struct i2c_adapter *adapter, int addr); + static int i2c_parse_reals(int *nrels, void *buffer, int bufsize, + long *results, int magnitude); +-static int i2c_write_reals(int nrels, void *buffer, int *bufsize, ++static int i2c_write_reals(int nrels, void *buffer, size_t *bufsize, + long *results, int magnitude); + static int i2c_proc_chips(ctl_table * ctl, int write, + struct file *filp, void *buffer, +@@ -55,22 +52,10 @@ + void *newval, size_t newlen, + void **context); + +-int __init sensors_init(void); +- + #define SENSORS_ENTRY_MAX 20 + static struct ctl_table_header *i2c_entries[SENSORS_ENTRY_MAX]; + + static struct i2c_client *i2c_clients[SENSORS_ENTRY_MAX]; +-static unsigned short i2c_inodes[SENSORS_ENTRY_MAX]; +- +-static ctl_table sysctl_table[] = { +- {CTL_DEV, "dev", NULL, 0, 0555}, +- {0}, +- {DEV_SENSORS, "sensors", NULL, 0, 0555}, +- {0}, +- {0, NULL, NULL, 0, 0555}, +- {0} +-}; + + static ctl_table i2c_proc_dev_sensors[] = { + {SENSORS_CHIPS, "chips", NULL, 0, 0644, NULL, &i2c_proc_chips, +@@ -91,31 +76,45 @@ + + + static struct ctl_table_header *i2c_proc_header; +-static int i2c_initialized; + + /* This returns a nice name for a new directory; for example lm78-isa-0310 + (for a LM78 chip on the ISA bus at port 0x310), or lm75-i2c-3-4e (for + a LM75 chip on the third i2c bus at address 0x4e). + name is allocated first. */ +-int i2c_create_name(char **name, const char *prefix, +- struct i2c_adapter *adapter, int addr) ++static char *generate_name(struct i2c_client *client, const char *prefix) + { +- char name_buffer[50]; +- int id; +- if (i2c_is_isa_adapter(adapter)) ++ struct i2c_adapter *adapter = client->adapter; ++ int addr = client->addr; ++ char name_buffer[50], *name; ++ ++ if (i2c_is_isa_adapter(adapter)) { + sprintf(name_buffer, "%s-isa-%04x", prefix, addr); +- else { +- if ((id = i2c_adapter_id(adapter)) < 0) +- return -ENOENT; ++ } else if (adapter->algo->smbus_xfer || adapter->algo->master_xfer) { ++ int id = i2c_adapter_id(adapter); ++ if (id < 0) ++ return ERR_PTR(-ENOENT); + sprintf(name_buffer, "%s-i2c-%d-%02x", prefix, id, addr); ++ } else { /* dummy adapter, generate prefix */ ++ int end, i; ++ ++ sprintf(name_buffer, "%s-", prefix); ++ end = strlen(name_buffer); ++ ++ for (i = 0; i < 32; i++) { ++ if (adapter->algo->name[i] == ' ') ++ break; ++ name_buffer[end++] = tolower(adapter->algo->name[i]); ++ } ++ ++ name_buffer[end] = 0; ++ sprintf(name_buffer + end, "-%04x", addr); + } +- *name = kmalloc(strlen(name_buffer) + 1, GFP_KERNEL); +- if (!*name) { +- printk (KERN_WARNING "i2c_create_name: not enough memory\n"); +- return -ENOMEM; +- } +- strcpy(*name, name_buffer); +- return 0; ++ ++ name = kmalloc(strlen(name_buffer) + 1, GFP_KERNEL); ++ if (!name) ++ return ERR_PTR(-ENOMEM); ++ strcpy(name, name_buffer); ++ return name; + } + + /* This rather complex function must be called when you want to add an entry +@@ -124,139 +123,91 @@ + ctl_template should be a template of the newly created directory. It is + copied in memory. The extra2 field of each file is set to point to client. + If any driver wants subdirectories within the newly created directory, +- this function must be updated! +- controlling_mod is the controlling module. It should usually be +- THIS_MODULE when calling. Note that this symbol is not defined in +- kernels before 2.3.13; define it to NULL in that case. We will not use it +- for anything older than 2.3.27 anyway. */ ++ this function must be updated! */ + int i2c_register_entry(struct i2c_client *client, const char *prefix, +- ctl_table * ctl_template, +- struct module *controlling_mod) ++ struct ctl_table *ctl_template) + { +- int i, res, len, id; +- ctl_table *new_table; +- char *name; +- struct ctl_table_header *new_header; +- +- if ((res = i2c_create_name(&name, prefix, client->adapter, +- client->addr))) return res; ++ struct { struct ctl_table root[2], dev[2], sensors[2]; } *tbl; ++ struct ctl_table_header *hdr; ++ struct ctl_table *tmp, *leaf; ++ const char *name; ++ int id, len = 0; + +- for (id = 0; id < SENSORS_ENTRY_MAX; id++) +- if (!i2c_entries[id]) { +- break; +- } +- if (id == SENSORS_ENTRY_MAX) { +- kfree(name); +- return -ENOMEM; +- } +- id += 256; ++ name = generate_name(client, prefix); ++ if (IS_ERR(name)) ++ return PTR_ERR(name); + +- len = 0; +- while (ctl_template[len].procname) +- len++; +- len += 7; +- if (!(new_table = kmalloc(sizeof(ctl_table) * len, GFP_KERNEL))) { +- kfree(name); +- return -ENOMEM; +- } +- +- memcpy(new_table, sysctl_table, 6 * sizeof(ctl_table)); +- new_table[0].child = &new_table[2]; +- new_table[2].child = &new_table[4]; +- new_table[4].child = &new_table[6]; +- new_table[4].procname = name; +- new_table[4].ctl_name = id; +- memcpy(new_table + 6, ctl_template, (len - 6) * sizeof(ctl_table)); +- for (i = 6; i < len; i++) +- new_table[i].extra2 = client; +- +- if (!(new_header = register_sysctl_table(new_table, 0))) { +- kfree(new_table); +- kfree(name); +- return -ENOMEM; ++ for (id = 0; id < SENSORS_ENTRY_MAX; id++) { ++ if (!i2c_entries[id]) ++ goto free_slot; + } + +- i2c_entries[id - 256] = new_header; ++ goto out_free_name; + +- i2c_clients[id - 256] = client; +-#ifdef DEBUG +- if (!new_header || !new_header->ctl_table || +- !new_header->ctl_table->child || +- !new_header->ctl_table->child->child || +- !new_header->ctl_table->child->child->de) { +- printk +- ("i2c-proc.o: NULL pointer when trying to install fill_inode fix!\n"); +- return id; +- } +-#endif /* DEBUG */ +- i2c_inodes[id - 256] = +- new_header->ctl_table->child->child->de->low_ino; +- new_header->ctl_table->child->child->de->owner = controlling_mod; +- +- return id; ++ free_slot: ++ while (ctl_template[len].ctl_name) ++ len++; ++ tbl = kmalloc(sizeof(*tbl) + sizeof(ctl_table) * (len + 1), ++ GFP_KERNEL); ++ if (!tbl) ++ goto out_free_name; ++ memset(tbl, 0, sizeof(*tbl)); ++ ++ /* The client sysctls */ ++ leaf = (struct ctl_table *) (tbl + 1); ++ memcpy(leaf, ctl_template, sizeof(ctl_table) * (len+1)); ++ for (tmp = leaf; tmp->ctl_name; tmp++) ++ tmp->extra2 = client; ++ ++ tbl->sensors->ctl_name = id+256; ++ tbl->sensors->procname = name; ++ tbl->sensors->mode = 0555; ++ tbl->sensors->child = leaf; ++ ++ tbl->dev->ctl_name = DEV_SENSORS; ++ tbl->dev->procname = "sensors"; ++ tbl->dev->mode = 0555; ++ tbl->dev->child = tbl->sensors; ++ ++ tbl->root->ctl_name = CTL_DEV; ++ tbl->root->procname = "dev"; ++ tbl->root->mode = 0555; ++ tbl->root->child = tbl->dev; ++ ++ hdr = register_sysctl_table(tbl->root, 0); ++ if (!hdr) ++ goto out_free_tbl; ++ ++ i2c_entries[id] = hdr; ++ i2c_clients[id] = client; ++ ++ return (id + 256); /* XXX(hch) why?? */ ++ ++ out_free_tbl: ++ kfree(tbl); ++ out_free_name: ++ kfree(name); ++ return -ENOMEM; + } + + void i2c_deregister_entry(int id) + { +- ctl_table *table; +- char *temp; + id -= 256; +- if (i2c_entries[id]) { +- table = i2c_entries[id]->ctl_table; +- unregister_sysctl_table(i2c_entries[id]); +- /* 2-step kfree needed to keep gcc happy about const points */ +- (const char *) temp = table[4].procname; +- kfree(temp); +- kfree(table); +- i2c_entries[id] = NULL; +- i2c_clients[id] = NULL; +- } +-} + +-/* Monitor access for /proc/sys/dev/sensors; make unloading i2c-proc.o +- impossible if some process still uses it or some file in it */ +-void i2c_fill_inode(struct inode *inode, int fill) +-{ +- if (fill) +- MOD_INC_USE_COUNT; +- else +- MOD_DEC_USE_COUNT; +-} +- +-/* Monitor access for /proc/sys/dev/sensors/ directories; make unloading +- the corresponding module impossible if some process still uses it or +- some file in it */ +-void i2c_dir_fill_inode(struct inode *inode, int fill) +-{ +- int i; +- struct i2c_client *client; ++ if (i2c_entries[id]) { ++ struct ctl_table_header *hdr = i2c_entries[id]; ++ struct ctl_table *tbl = hdr->ctl_table; + +-#ifdef DEBUG +- if (!inode) { +- printk("i2c-proc.o: Warning: inode NULL in fill_inode()\n"); +- return; ++ unregister_sysctl_table(hdr); ++ kfree(tbl->child->child->procname); ++ kfree(tbl); /* actually the whole anonymous struct */ + } +-#endif /* def DEBUG */ + +- for (i = 0; i < SENSORS_ENTRY_MAX; i++) +- if (i2c_clients[i] +- && (i2c_inodes[i] == inode->i_ino)) break; +-#ifdef DEBUG +- if (i == SENSORS_ENTRY_MAX) { +- printk +- ("i2c-proc.o: Warning: inode (%ld) not found in fill_inode()\n", +- inode->i_ino); +- return; +- } +-#endif /* def DEBUG */ +- client = i2c_clients[i]; +- if (fill) +- client->driver->inc_use(client); +- else +- client->driver->dec_use(client); ++ i2c_entries[id] = NULL; ++ i2c_clients[id] = NULL; + } + +-int i2c_proc_chips(ctl_table * ctl, int write, struct file *filp, ++static int i2c_proc_chips(ctl_table * ctl, int write, struct file *filp, + void *buffer, size_t * lenp) + { + char BUF[SENSORS_PREFIX_MAX + 30]; +@@ -294,7 +245,7 @@ + return 0; + } + +-int i2c_sysctl_chips(ctl_table * table, int *name, int nlen, ++static int i2c_sysctl_chips(ctl_table * table, int *name, int nlen, + void *oldval, size_t * oldlenp, void *newval, + size_t newlen, void **context) + { +@@ -456,7 +407,7 @@ + WARNING! This is tricky code. I have tested it, but there may still be + hidden bugs in it, even leading to crashes and things! + */ +-int i2c_parse_reals(int *nrels, void *buffer, int bufsize, ++static int i2c_parse_reals(int *nrels, void *buffer, int bufsize, + long *results, int magnitude) + { + int maxels, min, mag; +@@ -557,7 +508,7 @@ + return 0; + } + +-int i2c_write_reals(int nrels, void *buffer, int *bufsize, ++static int i2c_write_reals(int nrels, void *buffer, size_t *bufsize, + long *results, int magnitude) + { + #define BUFLEN 20 +@@ -646,6 +597,7 @@ + I2C_FUNC_SMBUS_QUICK)) return -1; + + for (addr = 0x00; addr <= (is_isa ? 0xffff : 0x7f); addr++) { ++ /* XXX: WTF is going on here??? */ + if ((is_isa && check_region(addr, 1)) || + (!is_isa && i2c_check_addr(adapter, addr))) + continue; +@@ -846,46 +798,33 @@ + return 0; + } + +-int __init sensors_init(void) ++static int __init i2c_proc_init(void) + { + printk(KERN_INFO "i2c-proc.o version %s (%s)\n", I2C_VERSION, I2C_DATE); +- i2c_initialized = 0; + if (! + (i2c_proc_header = +- register_sysctl_table(i2c_proc, 0))) return -ENOMEM; ++ register_sysctl_table(i2c_proc, 0))) { ++ printk(KERN_ERR "i2c-proc.o: error: sysctl interface not supported by kernel!\n"); ++ return -EPERM; ++ } + i2c_proc_header->ctl_table->child->de->owner = THIS_MODULE; +- i2c_initialized++; + return 0; + } + ++static void __exit i2c_proc_exit(void) ++{ ++ unregister_sysctl_table(i2c_proc_header); ++} ++ ++EXPORT_SYMBOL(i2c_register_entry); + EXPORT_SYMBOL(i2c_deregister_entry); +-EXPORT_SYMBOL(i2c_detect); + EXPORT_SYMBOL(i2c_proc_real); +-EXPORT_SYMBOL(i2c_register_entry); + EXPORT_SYMBOL(i2c_sysctl_real); +- +-#ifdef MODULE ++EXPORT_SYMBOL(i2c_detect); + + MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>"); + MODULE_DESCRIPTION("i2c-proc driver"); + MODULE_LICENSE("GPL"); + +-int i2c_cleanup(void) +-{ +- if (i2c_initialized >= 1) { +- unregister_sysctl_table(i2c_proc_header); +- i2c_initialized--; +- } +- return 0; +-} +- +-int init_module(void) +-{ +- return sensors_init(); +-} +- +-int cleanup_module(void) +-{ +- return i2c_cleanup(); +-} +-#endif /* MODULE */ ++module_init(i2c_proc_init); ++module_exit(i2c_proc_exit); +--- linux-old/include/linux/i2c-proc.h Tue Nov 6 00:55:29 2001 ++++ linux/include/linux/i2c-proc.h Mon Dec 13 19:26:36 2004 +@@ -1,6 +1,7 @@ + /* +- sensors.h - Part of lm_sensors, Linux kernel modules for hardware +- monitoring ++ i2c-proc.h - Part of the i2c package ++ was originally sensors.h - Part of lm_sensors, Linux kernel modules ++ for hardware monitoring + Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl> + + This program is free software; you can redistribute it and/or modify +@@ -18,14 +19,9 @@ + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +-#ifndef SENSORS_SENSORS_H +-#define SENSORS_SENSORS_H ++#ifndef _LINUX_I2C_PROC_H ++#define _LINUX_I2C_PROC_H + +-#ifdef __KERNEL__ +- +-/* Next two must be included before sysctl.h can be included, in 2.0 kernels */ +-#include <linux/types.h> +-#include <linux/fs.h> + #include <linux/sysctl.h> + + /* The type of callback functions used in sensors_{proc,sysctl}_real */ +@@ -73,8 +69,7 @@ + these functions must be updated! */ + extern int i2c_register_entry(struct i2c_client *client, + const char *prefix, +- ctl_table * ctl_template, +- struct module *controlling_mod); ++ ctl_table * ctl_template); + + extern void i2c_deregister_entry(int id); + +@@ -347,6 +342,31 @@ + {NULL}}; \ + SENSORS_INSMOD + ++#define SENSORS_INSMOD_8(chip1,chip2,chip3,chip4,chip5,chip6,chip7,chip8) \ ++ enum chips { any_chip, chip1, chip2, chip3, chip4, chip5, chip6, chip7, chip8 }; \ ++ SENSORS_MODULE_PARM(force, \ ++ "List of adapter,address pairs to boldly assume " \ ++ "to be present"); \ ++ SENSORS_MODULE_PARM_FORCE(chip1); \ ++ SENSORS_MODULE_PARM_FORCE(chip2); \ ++ SENSORS_MODULE_PARM_FORCE(chip3); \ ++ SENSORS_MODULE_PARM_FORCE(chip4); \ ++ SENSORS_MODULE_PARM_FORCE(chip5); \ ++ SENSORS_MODULE_PARM_FORCE(chip6); \ ++ SENSORS_MODULE_PARM_FORCE(chip7); \ ++ SENSORS_MODULE_PARM_FORCE(chip8); \ ++ static struct i2c_force_data forces[] = {{force,any_chip}, \ ++ {force_ ## chip1,chip1}, \ ++ {force_ ## chip2,chip2}, \ ++ {force_ ## chip3,chip3}, \ ++ {force_ ## chip4,chip4}, \ ++ {force_ ## chip5,chip5}, \ ++ {force_ ## chip6,chip6}, \ ++ {force_ ## chip7,chip7}, \ ++ {force_ ## chip8,chip8}, \ ++ {NULL}}; \ ++ SENSORS_INSMOD ++ + typedef int i2c_found_addr_proc(struct i2c_adapter *adapter, + int addr, unsigned short flags, + int kind); +@@ -362,7 +382,7 @@ + + /* This macro is used to scale user-input to sensible values in almost all + chip drivers. */ +-extern inline int SENSORS_LIMIT(long value, long low, long high) ++static inline int SENSORS_LIMIT(long value, long low, long high) + { + if (value < low) + return low; +@@ -372,8 +392,6 @@ + return value; + } + +-#endif /* def __KERNEL__ */ +- + + /* The maximum length of the prefix */ + #define SENSORS_PREFIX_MAX 20 +@@ -392,5 +410,5 @@ + char name[SENSORS_PREFIX_MAX + 13]; + }; + +-#endif /* def SENSORS_SENSORS_H */ ++#endif /* def _LINUX_I2C_PROC_H */ + +--- linux-old/drivers/i2c/i2c-rpx.c Thu Jan 1 00:00:00 1970 ++++ linux/drivers/i2c/i2c-rpx.c Mon Dec 13 19:26:36 2004 +@@ -0,0 +1,101 @@ ++/* ++ * 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/module.h> ++#include <linux/init.h> ++#include <linux/stddef.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, ++}; ++ ++static 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; ++} ++ ++static 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); +--- linux-old/drivers/i2c/i2c-velleman.c Tue Jan 20 15:10:31 2004 ++++ linux/drivers/i2c/i2c-velleman.c Mon Dec 13 19:26:36 2004 +@@ -18,18 +18,18 @@ + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + /* ------------------------------------------------------------------------- */ + +-/* $Id: i2c-velleman.c,v 1.19 2000/01/24 02:06:33 mds Exp $ */ ++/* $Id: i2c-velleman.c,v 1.33 2003/12/24 17:49:44 khali Exp $ */ + + #include <linux/kernel.h> + #include <linux/ioport.h> + #include <linux/module.h> + #include <linux/init.h> +-#include <linux/string.h> /* for 2.0 kernels to get NULL */ +-#include <asm/errno.h> /* for 2.0 kernels to get ENODEV */ +-#include <asm/io.h> +- ++#include <linux/errno.h> ++#include <linux/delay.h> + #include <linux/i2c.h> + #include <linux/i2c-algo-bit.h> ++#include <asm/io.h> ++#include <asm/param.h> /* for HZ */ + + /* ----- global defines ----------------------------------------------- */ + #define DEB(x) /* should be reasonable open, close &c. */ +@@ -90,75 +90,38 @@ + + static int bit_velle_init(void) + { +- if (check_region(base,(base == 0x3bc)? 3 : 8) < 0 ) { +- DEBE(printk("i2c-velleman.o: Port %#x already in use.\n", +- base)); ++ if (!request_region(base, (base == 0x3bc) ? 3 : 8, ++ "i2c (Vellemann adapter)")) + return -ENODEV; +- } else { +- request_region(base, (base == 0x3bc)? 3 : 8, +- "i2c (Vellemann adapter)"); +- bit_velle_setsda((void*)base,1); +- bit_velle_setscl((void*)base,1); +- } +- return 0; +-} + +-static void __exit bit_velle_exit(void) +-{ +- release_region( base , (base == 0x3bc)? 3 : 8 ); +-} +- +- +-static int bit_velle_reg(struct i2c_client *client) +-{ +- return 0; +-} +- +-static int bit_velle_unreg(struct i2c_client *client) +-{ ++ bit_velle_setsda((void*)base,1); ++ bit_velle_setscl((void*)base,1); + return 0; + } + +-static void bit_velle_inc_use(struct i2c_adapter *adap) +-{ +-#ifdef MODULE +- MOD_INC_USE_COUNT; +-#endif +-} +- +-static void bit_velle_dec_use(struct i2c_adapter *adap) +-{ +-#ifdef MODULE +- MOD_DEC_USE_COUNT; +-#endif +-} +- + /* ------------------------------------------------------------------------ + * 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_bit_data bit_velle_data = { +- NULL, +- bit_velle_setsda, +- bit_velle_setscl, +- bit_velle_getsda, +- bit_velle_getscl, +- 10, 10, 100, /* waits, timeout */ ++ .setsda = bit_velle_setsda, ++ .setscl = bit_velle_setscl, ++ .getsda = bit_velle_getsda, ++ .getscl = bit_velle_getscl, ++ .udelay = 10, ++ .mdelay = 10, ++ .timeout = HZ + }; + + static struct i2c_adapter bit_velle_ops = { +- "Velleman K8000", +- I2C_HW_B_VELLE, +- NULL, +- &bit_velle_data, +- bit_velle_inc_use, +- bit_velle_dec_use, +- bit_velle_reg, +- bit_velle_unreg, ++ .owner = THIS_MODULE, ++ .name = "Velleman K8000", ++ .id = I2C_HW_B_VELLE, ++ .algo_data = &bit_velle_data, + }; + +-int __init i2c_bitvelle_init(void) ++static int __init i2c_bitvelle_init(void) + { + printk(KERN_INFO "i2c-velleman.o: i2c Velleman K8000 adapter module version %s (%s)\n", I2C_VERSION, I2C_DATE); + if (base==0) { +@@ -184,24 +147,19 @@ + return 0; + } + ++static void __exit i2c_bitvelle_exit(void) ++{ ++ i2c_bit_del_bus(&bit_velle_ops); ++ release_region(base, (base == 0x3bc) ? 3 : 8); ++} ++ + EXPORT_NO_SYMBOLS; + +-#ifdef MODULE + MODULE_AUTHOR("Simon G. Vogl <simon@tk.uni-linz.ac.at>"); + MODULE_DESCRIPTION("I2C-Bus adapter routines for Velleman K8000 adapter"); + MODULE_LICENSE("GPL"); + + MODULE_PARM(base, "i"); + +-int init_module(void) +-{ +- return i2c_bitvelle_init(); +-} +- +-void cleanup_module(void) +-{ +- i2c_bit_del_bus(&bit_velle_ops); +- bit_velle_exit(); +-} +- +-#endif ++module_init(i2c_bitvelle_init); ++module_exit(i2c_bitvelle_exit); +--- linux-old/include/linux/i2c.h Tue Jan 20 15:10:34 2004 ++++ linux/include/linux/i2c.h Mon Dec 13 19:26:37 2004 +@@ -23,36 +23,33 @@ + /* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and + Frodo Looijaard <frodol@dds.nl> */ + +-/* $Id: i2c.h,v 1.46 2001/08/31 00:04:07 phil Exp $ */ ++/* $Id: i2c.h,v 1.80 2004/10/07 23:47:17 phil Exp $ */ + +-#ifndef I2C_H +-#define I2C_H ++#ifndef _LINUX_I2C_H ++#define _LINUX_I2C_H + +-#define I2C_DATE "20010830" +-#define I2C_VERSION "2.6.1" ++#define I2C_DATE "20041007" ++#define I2C_VERSION "2.8.8" + +-#include <linux/i2c-id.h> /* id values of adapters et. al. */ ++#include <linux/module.h> + #include <linux/types.h> +- +- +-struct i2c_msg; +- +- +-#ifdef __KERNEL__ +- +-/* --- Includes and compatibility declarations ------------------------ */ +- ++#include <linux/errno.h> ++#include <linux/sched.h> + #include <asm/semaphore.h> +-#include <linux/config.h> ++#include <linux/i2c-id.h> ++ ++#include <linux/version.h> ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,10) ++#define MODULE_LICENSE(x) ++#endif + + /* --- General options ------------------------------------------------ */ + +-#define I2C_ALGO_MAX 4 /* control memory consumption */ +-#define I2C_ADAP_MAX 16 ++#define I2C_ADAP_MAX 16 /* control memory consumption */ + #define I2C_DRIVER_MAX 16 + #define I2C_CLIENT_MAX 32 +-#define I2C_DUMMY_MAX 4 + ++struct i2c_msg; + struct i2c_algorithm; + struct i2c_adapter; + struct i2c_client; +@@ -60,7 +57,6 @@ + struct i2c_client_address_data; + union i2c_smbus_data; + +- + /* + * The master routines are the ones normally used to transmit data to devices + * on a bus (or read from them). Apart from two basic transfer functions to +@@ -113,6 +109,8 @@ + extern s32 i2c_smbus_write_block_data(struct i2c_client * client, + u8 command, u8 length, + u8 *values); ++extern s32 i2c_smbus_read_i2c_block_data(struct i2c_client * client, ++ u8 command, u8 *values); + extern s32 i2c_smbus_write_i2c_block_data(struct i2c_client * client, + u8 command, u8 length, + u8 *values); +@@ -125,6 +123,7 @@ + */ + + struct i2c_driver { ++ struct module *owner; + char name[32]; + int id; + unsigned int flags; /* div., see below */ +@@ -148,18 +147,6 @@ + * with the device. + */ + int (*command)(struct i2c_client *client,unsigned int cmd, void *arg); +- +- /* These two are mainly used for bookkeeping & dynamic unloading of +- * kernel modules. inc_use tells the driver that a client is being +- * used by another module & that it should increase its ref. counter. +- * dec_use is the inverse operation. +- * NB: Make sure you have no circular dependencies, or else you get a +- * deadlock when trying to unload the modules. +- * You should use the i2c_{inc,dec}_use_client functions instead of +- * calling this function directly. +- */ +- void (*inc_use)(struct i2c_client *client); +- void (*dec_use)(struct i2c_client *client); + }; + + /* +@@ -192,6 +179,7 @@ + * to name two of the most common. + */ + struct i2c_algorithm { ++ struct module *owner; /* future use --km */ + char name[32]; /* textual description */ + unsigned int id; + +@@ -221,16 +209,13 @@ + * with the access algorithms necessary to access it. + */ + struct i2c_adapter { ++ struct module *owner; + char name[32]; /* some useful name to identify the adapter */ + unsigned int id;/* == is algo->id | hwdep.struct->id, */ + /* for registered values see below */ + struct i2c_algorithm *algo;/* the algorithm to access the bus */ + void *algo_data; + +- /* --- These may be NULL, but should increase the module use count */ +- void (*inc_use)(struct i2c_adapter *); +- void (*dec_use)(struct i2c_adapter *); +- + /* --- administration stuff. */ + int (*client_register)(struct i2c_client *); + int (*client_unregister)(struct i2c_client *); +@@ -241,11 +226,11 @@ + /* and can be set via the i2c_ioctl call */ + + /* data fields that are valid for all devices */ +- struct semaphore lock; ++ struct semaphore bus; ++ struct semaphore list; + unsigned int flags;/* flags specifying div. data */ + + struct i2c_client *clients[I2C_CLIENT_MAX]; +- int client_count; + + int timeout; + int retries; +@@ -264,6 +249,9 @@ + #define I2C_CLIENT_ALLOW_USE 0x01 /* Client allows access */ + #define I2C_CLIENT_ALLOW_MULTIPLE_USE 0x02 /* Allow multiple access-locks */ + /* on an i2c_client */ ++#define I2C_CLIENT_PEC 0x04 /* Use Packet Error Checking */ ++#define I2C_CLIENT_TEN 0x10 /* we have a ten bit chip address */ ++ /* Must equal I2C_M_TEN below */ + + /* i2c_client_address_data is the struct for holding default client + * addresses for a driver and for the parameters supplied on the +@@ -302,12 +290,6 @@ + extern int i2c_attach_client(struct i2c_client *); + extern int i2c_detach_client(struct i2c_client *); + +-/* Only call these if you grab a resource that makes unloading the +- client and the adapter it is on completely impossible. Like when a +- /proc directory is entered. */ +-extern void i2c_inc_use_client(struct i2c_client *); +-extern void i2c_dec_use_client(struct i2c_client *); +- + /* New function: This is to get an i2c_client-struct for controlling the + client either by using i2c_control-function or having the + client-module export functions that can be used with the i2c_client +@@ -341,6 +323,15 @@ + struct i2c_client_address_data *address_data, + i2c_client_found_addr_proc *found_proc); + ++static inline int i2c_client_command(struct i2c_client *client, ++ unsigned int cmd, void *arg) ++{ ++ if (client->driver && client->driver->command) ++ return client->driver->command(client, cmd, arg); ++ else ++ return -EINVAL; ++} ++ + /* An ioctl like call to set div. parameters of the adapter. + */ + extern int i2c_control(struct i2c_client *,unsigned int, unsigned long); +@@ -358,8 +349,6 @@ + /* Return 1 if adapter supports everything we need, 0 if not. */ + extern int i2c_check_functionality (struct i2c_adapter *adap, u32 func); + +-#endif /* __KERNEL__ */ +- + /* + * I2C Message - used for pure i2c transaction, also from /dev interface + */ +@@ -370,15 +359,28 @@ + #define I2C_M_RD 0x01 + #define I2C_M_NOSTART 0x4000 + #define I2C_M_REV_DIR_ADDR 0x2000 ++#define I2C_M_IGNORE_NAK 0x1000 ++#define I2C_M_NO_RD_ACK 0x0800 ++#define I2C_M_RECV_LEN 0x0400 /* length will be first received byte */ ++#define I2C_M_RECV_PEC 0x0200 /* receive one more than the returned ++ length byte for the PEC */ + __u16 len; /* msg length */ + __u8 *buf; /* pointer to msg data */ ++ int err; ++ short done; + }; + + /* To determine what functionality is present */ + + #define I2C_FUNC_I2C 0x00000001 + #define I2C_FUNC_10BIT_ADDR 0x00000002 +-#define I2C_FUNC_PROTOCOL_MANGLING 0x00000004 /* I2C_M_{REV_DIR_ADDR,NOSTART} */ ++#define I2C_FUNC_PROTOCOL_MANGLING 0x00000004 /* I2C_M_{REV_DIR_ADDR,NOSTART,..} */ ++#define I2C_FUNC_SMBUS_HWPEC_CALC 0x00000008 /* SMBus 2.0 */ ++#define I2C_FUNC_SMBUS_READ_WORD_DATA_PEC 0x00000800 /* SMBus 2.0 */ ++#define I2C_FUNC_SMBUS_WRITE_WORD_DATA_PEC 0x00001000 /* SMBus 2.0 */ ++#define I2C_FUNC_SMBUS_PROC_CALL_PEC 0x00002000 /* SMBus 2.0 */ ++#define I2C_FUNC_SMBUS_BLOCK_PROC_CALL_PEC 0x00004000 /* SMBus 2.0 */ ++#define I2C_FUNC_SMBUS_BLOCK_PROC_CALL 0x00008000 /* SMBus 2.0 */ + #define I2C_FUNC_SMBUS_QUICK 0x00010000 + #define I2C_FUNC_SMBUS_READ_BYTE 0x00020000 + #define I2C_FUNC_SMBUS_WRITE_BYTE 0x00040000 +@@ -389,8 +391,12 @@ + #define I2C_FUNC_SMBUS_PROC_CALL 0x00800000 + #define I2C_FUNC_SMBUS_READ_BLOCK_DATA 0x01000000 + #define I2C_FUNC_SMBUS_WRITE_BLOCK_DATA 0x02000000 +-#define I2C_FUNC_SMBUS_READ_I2C_BLOCK 0x04000000 /* New I2C-like block */ +-#define I2C_FUNC_SMBUS_WRITE_I2C_BLOCK 0x08000000 /* transfer */ ++#define I2C_FUNC_SMBUS_READ_I2C_BLOCK 0x04000000 /* I2C-like block xfer */ ++#define I2C_FUNC_SMBUS_WRITE_I2C_BLOCK 0x08000000 /* w/ 1-byte reg. addr. */ ++#define I2C_FUNC_SMBUS_READ_I2C_BLOCK_2 0x10000000 /* I2C-like block xfer */ ++#define I2C_FUNC_SMBUS_WRITE_I2C_BLOCK_2 0x20000000 /* w/ 2-byte reg. addr. */ ++#define I2C_FUNC_SMBUS_READ_BLOCK_DATA_PEC 0x40000000 /* SMBus 2.0 */ ++#define I2C_FUNC_SMBUS_WRITE_BLOCK_DATA_PEC 0x80000000 /* SMBus 2.0 */ + + #define I2C_FUNC_SMBUS_BYTE I2C_FUNC_SMBUS_READ_BYTE | \ + I2C_FUNC_SMBUS_WRITE_BYTE +@@ -402,13 +408,28 @@ + I2C_FUNC_SMBUS_WRITE_BLOCK_DATA + #define I2C_FUNC_SMBUS_I2C_BLOCK I2C_FUNC_SMBUS_READ_I2C_BLOCK | \ + I2C_FUNC_SMBUS_WRITE_I2C_BLOCK ++#define I2C_FUNC_SMBUS_I2C_BLOCK_2 I2C_FUNC_SMBUS_READ_I2C_BLOCK_2 | \ ++ I2C_FUNC_SMBUS_WRITE_I2C_BLOCK_2 ++#define I2C_FUNC_SMBUS_BLOCK_DATA_PEC I2C_FUNC_SMBUS_READ_BLOCK_DATA_PEC | \ ++ I2C_FUNC_SMBUS_WRITE_BLOCK_DATA_PEC ++#define I2C_FUNC_SMBUS_WORD_DATA_PEC I2C_FUNC_SMBUS_READ_WORD_DATA_PEC | \ ++ I2C_FUNC_SMBUS_WRITE_WORD_DATA_PEC ++ ++#define I2C_FUNC_SMBUS_READ_BYTE_PEC I2C_FUNC_SMBUS_READ_BYTE_DATA ++#define I2C_FUNC_SMBUS_WRITE_BYTE_PEC I2C_FUNC_SMBUS_WRITE_BYTE_DATA ++#define I2C_FUNC_SMBUS_READ_BYTE_DATA_PEC I2C_FUNC_SMBUS_READ_WORD_DATA ++#define I2C_FUNC_SMBUS_WRITE_BYTE_DATA_PEC I2C_FUNC_SMBUS_WRITE_WORD_DATA ++#define I2C_FUNC_SMBUS_BYTE_PEC I2C_FUNC_SMBUS_BYTE_DATA ++#define I2C_FUNC_SMBUS_BYTE_DATA_PEC I2C_FUNC_SMBUS_WORD_DATA + + #define I2C_FUNC_SMBUS_EMUL I2C_FUNC_SMBUS_QUICK | \ + I2C_FUNC_SMBUS_BYTE | \ + I2C_FUNC_SMBUS_BYTE_DATA | \ + I2C_FUNC_SMBUS_WORD_DATA | \ + I2C_FUNC_SMBUS_PROC_CALL | \ +- I2C_FUNC_SMBUS_WRITE_BLOCK_DATA ++ I2C_FUNC_SMBUS_WRITE_BLOCK_DATA | \ ++ I2C_FUNC_SMBUS_WRITE_BLOCK_DATA_PEC | \ ++ I2C_FUNC_SMBUS_I2C_BLOCK + + /* + * Data for SMBus Messages +@@ -418,8 +439,9 @@ + union i2c_smbus_data { + __u8 byte; + __u16 word; +- __u8 block[I2C_SMBUS_BLOCK_MAX + 2]; /* block[0] is used for length */ ++ __u8 block[I2C_SMBUS_BLOCK_MAX + 3]; /* block[0] is used for length */ + /* one more for read length in block process call */ ++ /* and one more for PEC */ + }; + + /* smbus_access read or write markers */ +@@ -435,6 +457,11 @@ + #define I2C_SMBUS_PROC_CALL 4 + #define I2C_SMBUS_BLOCK_DATA 5 + #define I2C_SMBUS_I2C_BLOCK_DATA 6 ++#define I2C_SMBUS_BLOCK_PROC_CALL 7 /* SMBus 2.0 */ ++#define I2C_SMBUS_BLOCK_DATA_PEC 8 /* SMBus 2.0 */ ++#define I2C_SMBUS_PROC_CALL_PEC 9 /* SMBus 2.0 */ ++#define I2C_SMBUS_BLOCK_PROC_CALL_PEC 10 /* SMBus 2.0 */ ++#define I2C_SMBUS_WORD_DATA_PEC 11 /* SMBus 2.0 */ + + + /* ----- commands for the ioctl like i2c_command call: +@@ -460,6 +487,7 @@ + + #define I2C_FUNCS 0x0705 /* Get the adapter functionality */ + #define I2C_RDWR 0x0707 /* Combined R/W transfer (one stop only)*/ ++#define I2C_PEC 0x0708 /* != 0 for SMBus PEC */ + #if 0 + #define I2C_ACK_TEST 0x0710 /* See if a slave is at a specific address */ + #endif +@@ -475,16 +503,6 @@ + + #define I2C_MAJOR 89 /* Device major number */ + +-#ifdef __KERNEL__ +- +-# ifndef NULL +-# define NULL ( (void *) 0 ) +-# endif +- +-# ifndef ENODEV +-# include <asm/errno.h> +-# endif +- + /* These defines are used for probing i2c client addresses */ + /* Default fill of many variables */ + #define I2C_CLIENT_DEFAULTS {I2C_CLIENT_END, I2C_CLIENT_END, I2C_CLIENT_END, \ +@@ -546,5 +564,11 @@ + #define i2c_is_isa_adapter(adapptr) \ + ((adapptr)->algo->id == I2C_ALGO_ISA) + +-#endif /* def __KERNEL__ */ +-#endif /* I2C_H */ ++/* Tiny delay function used by the i2c bus drivers */ ++static inline void i2c_delay(signed long timeout) ++{ ++ set_current_state(TASK_INTERRUPTIBLE); ++ schedule_timeout(timeout); ++} ++ ++#endif /* _LINUX_I2C_H */ |