--- linux-old/Documentation/Configure.help Fri Nov 18 20:08:35 2005 +++ linux/Documentation/Configure.help Sun Dec 4 15:23:54 2005 @@ -19368,6 +19368,16 @@ . 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 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 + . + 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. @@ -19389,6 +19399,15 @@ . 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 + . + 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 @@ -19426,6 +19445,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 + . + 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 + . + 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 + . + 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 + . + 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 + . + 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/drivers/i2c/Config.in Wed Apr 14 13:05:29 2004 +++ linux/drivers/i2c/Config.in Sun Dec 4 15:23:54 2005 @@ -12,6 +12,10 @@ dep_tristate ' Philips style parallel port adapter' CONFIG_I2C_PHILIPSPAR $CONFIG_I2C_ALGOBIT $CONFIG_PARPORT dep_tristate ' ELV adapter' CONFIG_I2C_ELV $CONFIG_I2C_ALGOBIT dep_tristate ' Velleman K8000 adapter' CONFIG_I2C_VELLEMAN $CONFIG_I2C_ALGOBIT + dep_tristate ' Basic I2C on Parallel Port' CONFIG_I2C_PPORT $CONFIG_I2C_ALGOBIT + if [ "$CONFIG_ARCH_SA1100" = "y" ]; then + dep_tristate 'SA1100 I2C Adapter' CONFIG_I2C_FRODO $CONFIG_I2C_ALGOBIT + fi dep_tristate ' NatSemi SCx200 I2C using GPIO pins' CONFIG_SCx200_I2C $CONFIG_SCx200_GPIO $CONFIG_I2C_ALGOBIT if [ "$CONFIG_SCx200_I2C" != "n" ]; then int ' GPIO pin used for SCL' CONFIG_SCx200_I2C_SCL 12 @@ -24,6 +28,7 @@ dep_tristate 'I2C PCF 8584 interfaces' CONFIG_I2C_ALGOPCF $CONFIG_I2C if [ "$CONFIG_I2C_ALGOPCF" != "n" ]; then dep_tristate ' Elektor ISA card' CONFIG_I2C_ELEKTOR $CONFIG_I2C_ALGOPCF + dep_tristate ' PCF on EPP port' CONFIG_I2C_PCFEPP $CONFIG_I2C_ALGOPCF fi if [ "$CONFIG_MIPS_ITE8172" = "y" ]; then @@ -58,6 +63,13 @@ dep_tristate 'I2C SGI interfaces' CONFIG_I2C_ALGO_SGI $CONFIG_I2C fi + if [ "$CONFIG_IBM_OCP" = "y" ]; then + dep_tristate 'IBM on-chip I2C Algorithm' CONFIG_I2C_IBM_OCP_ALGO $CONFIG_I2C + if [ "$CONFIG_I2C_IBM_OCP_ALGO" != "n" ]; then + dep_tristate ' IBM on-chip I2C Adapter' CONFIG_I2C_IBM_OCP_ADAP $CONFIG_I2C_IBM_OCP_ALGO + fi + fi + # This is needed for automatic patch generation: sensors code starts here # This is needed for automatic patch generation: sensors code ends here --- linux-old/drivers/i2c/Makefile Wed Feb 18 13:36:31 2004 +++ linux/drivers/i2c/Makefile Sun Dec 4 15:23:54 2005 @@ -6,6 +6,7 @@ export-objs := i2c-core.o i2c-algo-bit.o i2c-algo-pcf.o \ i2c-algo-ite.o i2c-algo-sibyte.o i2c-algo-sgi.o \ + i2c-algo-8xx.o i2c-algo-ibm_ocp.o \ i2c-proc.o obj-$(CONFIG_I2C) += i2c-core.o @@ -18,6 +19,13 @@ obj-$(CONFIG_I2C_ELEKTOR) += i2c-elektor.o obj-$(CONFIG_ITE_I2C_ALGO) += i2c-algo-ite.o obj-$(CONFIG_ITE_I2C_ADAP) += i2c-adap-ite.o +obj-$(CONFIG_I2C_PPORT) += i2c-pport.o +obj-$(CONFIG_I2C_FRODO) += i2c-frodo.o +obj-$(CONFIG_I2C_PCFEPP) += i2c-pcf-epp.o +obj-$(CONFIG_I2C_ALGO8XX) += i2c-algo-8xx.o +obj-$(CONFIG_I2C_RPXLITE) += i2c-rpx.o +obj-$(CONFIG_I2C_IBM_OCP_ALGO) += i2c-algo-ibm_ocp.o +obj-$(CONFIG_I2C_IBM_OCP_ADAP) += i2c-adap-ibm_ocp.o obj-$(CONFIG_I2C_PROC) += i2c-proc.o obj-$(CONFIG_SCx200_I2C) += scx200_i2c.o obj-$(CONFIG_SCx200_ACB) += scx200_acb.o --- linux-old/Documentation/i2c/dev-interface Wed Feb 18 13:36:30 2004 +++ linux/Documentation/i2c/dev-interface Sun Dec 4 15:23:54 2005 @@ -14,9 +14,12 @@ ========= So let's say you want to access an i2c adapter from a C program. The -first thing to do is `#include " and "#include . -Yes, I know, you should never include kernel header files, but until glibc -knows about i2c, there is not much choice. +first thing to do is "#include ". Please note that +there are two files named "i2c-dev.h" out there, one is distributed +with the Linux kernel and is meant to be included from kernel +driver code, the other one is distributed with lm_sensors and is +meant to be included from user-space programs. You obviously want +the second one here. Now, you have to decide which adapter you want to access. You should inspect /proc/bus/i2c to decide this. Adapter numbers are assigned @@ -78,7 +81,7 @@ ========================== The following IOCTLs are defined and fully supported -(see also i2c-dev.h and i2c.h): +(see also i2c-dev.h): ioctl(file,I2C_SLAVE,long addr) Change slave address. The address is passed in the 7 lower bits of the @@ -89,13 +92,18 @@ 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. -ioctl(file,I2C_RDWR,struct i2c_ioctl_rdwr_data *msgset) +ioctl(file,I2C_RDWR,struct i2c_rdwr_ioctl_data *msgset) Do combined read/write transaction without stop in between. - The argument is a pointer to a struct i2c_ioctl_rdwr_data { + The argument is a pointer to a struct i2c_rdwr_ioctl_data { struct i2c_msg *msgs; /* ptr to array of simple messages */ int nmsgs; /* number of messages to exchange */ --- linux-old/Documentation/i2c/functionality Fri Dec 29 22:35:47 2000 +++ linux/Documentation/i2c/functionality Sun Dec 4 15:23:54 2005 @@ -115,7 +115,7 @@ If you try to access an adapter from a userspace program, you will have to use the /dev interface. You will still have to check whether the functionality you need is supported, of course. This is done using -the I2C_FUNCS ioctl. An example, adapted from the lm_sensors i2c_detect +the I2C_FUNCS ioctl. An example, adapted from the lm_sensors i2cdetect program, is below: int file; --- linux-old/Documentation/i2c/i2c-pport Thu Jan 1 00:00:00 1970 +++ linux/Documentation/i2c/i2c-pport Sun Dec 4 15:23:54 2005 @@ -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 Wed Feb 18 13:36:30 2004 +++ linux/Documentation/i2c/i2c-protocol Sun Dec 4 15:23:54 2005 @@ -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 Wed Feb 18 13:36:30 2004 +++ linux/Documentation/i2c/summary Sun Dec 4 15:23:54 2005 @@ -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 Thu Apr 14 07:43:32 2005 +++ linux/Documentation/i2c/writing-clients Sun Dec 4 15:23:54 2005 @@ -28,11 +28,11 @@ .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 */ - .inc_use = &foo_inc_use, /* May be NULL */ - .dec_use = &foo_dec_use, /* May be NULL */ + .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 */ } The name can be chosen freely, and may be upto 40 characters long. Please @@ -58,32 +58,37 @@ 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). +and some process has entered that directory. + +i2c-core and i2c-proc will take care of properly counting the users +of the client driver for the common cases. If however your driver has +functions used by other parts of the kernel, you will have to implement +the inc_use and dec_use callback functions and use them. 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. +module has to implement its own callback functions. - void foo_inc_use (struct i2c_client *client) - { - #ifdef MODULE - MOD_INC_USE_COUNT; - #endif - } +static 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 - } +static 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 +Do not call these callback functions directly; instead, use the following functions defined in i2c.h: - void i2c_inc_use_client(struct i2c_client *); - void i2c_dec_use_client(struct i2c_client *); + +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 @@ -302,7 +307,7 @@ These are automatically translated to insmod variables of the form force_foo. -So we have a generic insmod variabled `force', and chip-specific variables +So we have a generic insmod variable `force', and chip-specific variables `force_CHIPNAME'. Fortunately, as a module writer, you just have to define the `normal' --- linux-old/drivers/i2c/i2c-adap-ibm_ocp.c Thu Jan 1 00:00:00 1970 +++ linux/drivers/i2c/i2c-adap-ibm_ocp.c Sun Dec 4 15:23:55 2005 @@ -0,0 +1,368 @@ +/* + ------------------------------------------------------------------------- + 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 and even + Frodo Looijaard + + + 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * 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; idata; + 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: If this compiled as a module, then increment the count +// +static void iic_ibmocp_inc_use(struct i2c_adapter *adap) +{ +#ifdef MODULE + MOD_INC_USE_COUNT; +#endif +} + + +// +// Description: If this is a module, then decrement the count +// +static void iic_ibmocp_dec_use(struct i2c_adapter *adap) +{ +#ifdef MODULE + MOD_DEC_USE_COUNT; +#endif +} + +// +// 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; iiic_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]->id = I2C_HW_OCP; + iic_ibmocp_ops[i]->algo = NULL; + iic_ibmocp_ops[i]->algo_data = iic_ibmocp_data[i]; + iic_ibmocp_ops[i]->inc_use = iic_ibmocp_inc_use; + iic_ibmocp_ops[i]->dec_use = iic_ibmocp_dec_use; + + + 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"); +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 Sun Dec 4 15:23:55 2005 @@ -0,0 +1,615 @@ +/* + * 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.15 2004/11/20 08:02:24 khali Exp $ */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#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 = { + .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 "); +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 Sun Dec 4 15:23:55 2005 @@ -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 Thu Apr 14 07:43:33 2005 +++ linux/drivers/i2c/i2c-algo-bit.c Sun Dec 4 15:23:55 2005 @@ -18,10 +18,10 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* ------------------------------------------------------------------------- */ -/* With some changes from Kyösti Mälkki and even - Frodo Looijaard */ +/* With some changes from Frodo Looijaard , Kyösti Mälkki + and Jean Delvare */ -/* $Id: i2c-algo-bit.c,v 1.30 2001/07/29 02:44:25 mds Exp $ */ +/* $Id: i2c-algo-bit.c,v 1.53 2005/04/30 19:53:50 khali Exp $ */ #include #include @@ -41,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: --------------- */ @@ -86,9 +72,6 @@ { setscl(adap,0); udelay(adap->udelay); -#ifdef SLO_IO - SLO_IO -#endif } /* @@ -97,23 +80,23 @@ */ 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; } @@ -121,9 +104,7 @@ schedule(); } DEBSTAT(printk(KERN_DEBUG "needed %ld jiffies\n", jiffies-start)); -#ifdef SLO_IO - SLO_IO -#endif + udelay(adap->udelay); return 0; } @@ -142,7 +123,7 @@ /* scl, sda may not be high */ DEBPROTO(printk(" Sr ")); setsda(adap,1); - setscl(adap,1); + sclhi(adap); udelay(adap->udelay); sdalo(adap); @@ -176,7 +157,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); @@ -184,6 +164,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: @@ -194,11 +175,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 ") ); @@ -217,11 +199,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; @@ -230,6 +211,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); } @@ -240,71 +223,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); @@ -338,16 +325,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; @@ -356,7 +348,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++; @@ -375,12 +367,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); @@ -393,6 +391,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 ")); @@ -417,31 +429,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; @@ -451,7 +466,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; } @@ -463,10 +478,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; } @@ -477,16 +492,18 @@ struct i2c_algo_bit_data *adap = i2c_adap->algo_data; int i,ret; + unsigned short nak_ok; i2c_start(adap); for (i=0;iflags & 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; @@ -494,14 +511,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; @@ -512,30 +529,24 @@ 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_I2C | I2C_FUNC_SMBUS_EMUL | - I2C_FUNC_10BIT_ADDR | I2C_FUNC_PROTOCOL_MANGLING; + I2C_FUNC_10BIT_ADDR | 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 */ + .name = "Bit-shift algorithm", + .id = I2C_ALGO_BIT, + .master_xfer = bit_xfer, + .functionality = bit_func, }; /* @@ -543,7 +554,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) { @@ -563,78 +573,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 "); 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 Tue Nov 22 08:50:22 2005 +++ linux/include/linux/i2c-algo-bit.h Sun Dec 4 15:23:55 2005 @@ -21,12 +21,10 @@ /* With some changes from Kyösti Mälkki and even Frodo Looijaard */ -/* $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 +#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 Sun Dec 4 15:23:55 2005 @@ -0,0 +1,900 @@ +/* + ------------------------------------------------------------------------- + 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 and + Frodo Looijaard ,and also from Martin Bailey + + + + 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* ----- 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; imdbuf, + 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; imdbuf, 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; iIssued 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; imdbuf); + // 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 irrelevant 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 = { + .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 "); +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 Sun Dec 4 15:23:55 2005 @@ -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 and even + Frodo Looijaard */ + +/* 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 Thu Apr 14 07:43:33 2005 +++ linux/drivers/i2c/i2c-algo-pcf.c Sun Dec 4 15:23:55 2005 @@ -36,7 +36,6 @@ #include #include #include -#include "i2c-pcf8584.h" /* ----- global defines ----------------------------------------------- */ @@ -50,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: --------------- */ @@ -147,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 */ } @@ -164,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; } @@ -425,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_I2C | I2C_FUNC_SMBUS_EMUL | @@ -440,14 +431,10 @@ /* -----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 */ + .name = "PCF8584 algorithm", + .id = I2C_ALGO_PCF, + .master_xfer = pcf_xfer, + .functionality = pcf_func, }; /* @@ -455,7 +442,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", @@ -473,81 +460,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 "); 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 Wed Jul 27 11:18:50 2005 +++ linux/include/linux/i2c-algo-pcf.h Sun Dec 4 15:23:55 2005 @@ -22,13 +22,12 @@ /* With some changes from Kyösti Mälkki and even Frodo Looijaard */ -/* $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 +#include 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 Thu Jun 2 14:39:06 2005 +++ linux/drivers/i2c/i2c-core.c Sun Dec 4 15:23:56 2005 @@ -18,56 +18,41 @@ /* ------------------------------------------------------------------------- */ /* With some changes from Kyösti Mälkki . - All SMBus-related things are written by Frodo Looijaard */ + All SMBus-related things are written by Frodo Looijaard + SMBus 2.0 support by Mark Studebaker */ -/* $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 #include #include #include #include -#include - -#include - -/* ----- compatibility stuff ----------------------------------------------- */ - #include - +#include #include /* ----- 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) +#if I2C_LINUX_2_4_BINARY_COMPATIBILITY +#define I2C_LOCK_LIST(adap) down(&adap->bus) +#define I2C_UNLOCK_LIST(adap) up(&adap->bus) +#else +#define I2C_LOCK_LIST(adap) down(&adap->list) +#define I2C_UNLOCK_LIST(adap) up(&adap->list) +#endif #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 +60,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 +68,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 +89,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 +102,41 @@ 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); +#if !I2C_LINUX_2_4_BINARY_COMPATIBILITY + init_MUTEX(&adap->list); +#endif /* inform drivers of new adapters */ - DRV_LOCK(); for (j=0;jflags&(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 +152,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; + "detached!\n", adap->name, drivers[j]->name); + 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;jclients[j]; if (client!=NULL) @@ -226,31 +173,20 @@ if ((res=client->driver->detach_client(client))) { printk(KERN_ERR "i2c-core.o: adapter %s not " "unregistered, because client at " - "address %02x can't be detached. ", + "address %02x can't be detached\n", adap->name, client->addr); 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 +200,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 +210,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 +224,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 +240,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 +252,6 @@ * invalid operation might (will!) result, when using stale client * pointers. */ - ADAP_LOCK(); /* should be moved inside the if statement... */ for (k=0;kname, + "not unloaded!\n", driver->name, adap->name); - ADAP_UNLOCK(); - return res; + goto ERROR0; } } else { for (j=0;jname, 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; + + I2C_LOCK_LIST(adapter); + rval = __i2c_check_addr(adapter, addr); + I2C_UNLOCK_LIST(adapter); + + return rval; +} + int i2c_attach_client(struct i2c_client *client) { struct i2c_adapter *adapter = client->adapter; @@ -398,6 +336,7 @@ if (i2c_check_addr(client->adapter,client->addr)) return -EBUSY; + I2C_LOCK_LIST(adapter); for (i = 0; i < I2C_CLIENT_MAX; i++) if (NULL == adapter->clients[i]) break; @@ -405,11 +344,11 @@ printk(KERN_WARNING " i2c-core.o: attach_client(%s) - enlarge I2C_CLIENT_MAX.\n", client->name); + I2C_UNLOCK_LIST(adapter); return -ENOMEM; } - adapter->clients[i] = client; - adapter->client_count++; + I2C_UNLOCK_LIST(adapter); if (adapter->client_register) if (adapter->client_register(client)) @@ -431,16 +370,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; @@ -448,33 +377,40 @@ if (adapter->client_unregister != NULL) if ((res = adapter->client_unregister(client))) { printk(KERN_ERR "i2c-core.o: client_unregister [%s] failed, " - "client not detached",client->name); + "client not detached\n", client->name); return res; } + I2C_LOCK_LIST(adapter); + 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); + I2C_UNLOCK_LIST(adapter); + return -ENODEV; + } adapter->clients[i] = NULL; - adapter->client_count--; + I2C_UNLOCK_LIST(adapter); 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); } -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); } @@ -548,15 +484,13 @@ 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 +523,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 +546,7 @@ adapters[i]->name, adapters[i]->algo->name); } + up(&core_lists); return nr; } @@ -621,98 +557,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; + I2C_LOCK_LIST(adap); + 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); + } + I2C_UNLOCK_LIST(adap); + 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 = THIS_MODULE; + 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 +691,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 { @@ -750,14 +713,14 @@ msg.addr = client->addr; msg.flags = client->flags & I2C_M_TEN; msg.len = count; - (const char *)msg.buf = buf; + msg.buf = (char *)buf; 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 +748,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 +928,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 +1063,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 +1153,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) { @@ -1104,7 +1222,7 @@ 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 +1258,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 +1290,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 +1362,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,135 +1454,34 @@ 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_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 - - /* -------------- 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); EXPORT_SYMBOL(i2c_get_client); EXPORT_SYMBOL(i2c_use_client); EXPORT_SYMBOL(i2c_release_client); @@ -1381,11 +1506,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 "); MODULE_DESCRIPTION("I2C-Bus main module"); MODULE_LICENSE("GPL"); @@ -1393,13 +1519,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 Wed Feb 18 13:36:31 2004 +++ linux/drivers/i2c/i2c-dev.c Sun Dec 4 15:23:56 2005 @@ -28,9 +28,8 @@ /* The devfs code is contributed by Philipp Matthias Hahn */ -/* $Id: i2c-dev.c,v 1.40 2001/08/25 01:28:01 mds Exp $ */ +/* $Id: i2c-dev.c,v 1.61 2005/05/19 20:50:29 khali Exp $ */ -#include #include #include #include @@ -39,21 +38,14 @@ #ifdef CONFIG_DEVFS_FS #include #endif - - -/* If you want debugging uncomment: */ -/* #define DEBUG */ - #include -#include - #include #include +#include + +/* 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,20 @@ #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, */ + .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", + .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 +118,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 +153,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 +175,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 +194,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, @@ -229,7 +211,7 @@ sizeof(rdwr_arg))) return -EFAULT; - /* Put an arbritrary limit on the number of messages that can + /* Put an arbitrary limit on the number of messages that can * be sent at once */ if (rdwr_arg.nmsgs > 42) return -EINVAL; @@ -318,7 +300,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 +344,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 +357,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 +372,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 +388,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->inc_use) + client->adapter->inc_use(client->adapter); #ifdef DEBUG printk(KERN_DEBUG "i2c-dev.o: opened i2c-%d\n",minor); @@ -417,16 +404,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->dec_use) + client->adapter->dec_use(client->adapter); + 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 +441,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 +469,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 +487,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 and Simon G. Vogl "); 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 Tue Nov 22 08:49:01 2005 +++ linux/include/linux/i2c-dev.h Sun Dec 4 15:23:56 2005 @@ -19,14 +19,17 @@ 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.15 2005/05/16 16:34:11 khali Exp $ */ +#ifndef _LINUX_I2C_DEV_H +#define _LINUX_I2C_DEV_H #include -#include +#include + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,18) +#define minor(d) MINOR(d) +#endif /* Some IOCTL commands are defined in */ /* Note: 10-bit addresses are NOT supported! */ @@ -45,137 +48,4 @@ __u32 nmsgs; /* number of i2c_msgs */ }; -#ifndef __KERNEL__ - -#include - -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 Wed Feb 18 13:36:31 2004 +++ linux/drivers/i2c/i2c-elektor.c Sun Dec 4 15:23:56 2005 @@ -31,23 +31,22 @@ #include #include #include +#include #include -#include -#include - +#include #include #include -#include -#include "i2c-pcf8584.h" +#include +#include #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,29 +165,6 @@ } -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 @@ -199,27 +185,25 @@ * 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, + .name = "PCF8584 ISA adapter", + .id = I2C_HW_P_ELEK, + .algo_data = &pcf_isa_data, + .inc_use = pcf_isa_inc_use, + .dec_use = pcf_isa_dec_use, }; -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 +261,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 "); MODULE_DESCRIPTION("I2C-Bus adapter routines for PCF8584 ISA bus adapter"); MODULE_LICENSE("GPL"); @@ -304,15 +307,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 Thu Oct 11 15:05:47 2001 +++ linux/include/linux/i2c-elektor.h Sun Dec 4 15:23:56 2005 @@ -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 and even - Frodo Looijaard */ - -/* $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 Wed Feb 18 13:36:31 2004 +++ linux/drivers/i2c/i2c-elv.c Sun Dec 4 15:23:56 2005 @@ -21,21 +21,18 @@ /* With some changes from Kyösti Mälkki and even Frodo Looijaard */ -/* $Id: i2c-elv.c,v 1.17 2001/07/29 02:44:25 mds Exp $ */ +/* $Id: i2c-elv.c,v 1.30 2004/11/25 21:43:45 khali Exp $ */ #include #include #include #include #include - -#include - #include -#include #include #include #include +#include #define DEFAULT_BASE 0x378 static int base=0; @@ -89,44 +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) -{ + PortData = 0; + bit_elv_setsda((void*)base,1); + bit_elv_setscl((void*)base,1); return 0; -} -static int bit_elv_unreg(struct i2c_client *client) -{ - return 0; +fail: + release_region(base , (base == 0x3bc) ? 3 : 8); + return -ENODEV; } static void bit_elv_inc_use(struct i2c_adapter *adap) @@ -148,26 +132,24 @@ * 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, + .name = "ELV Parallel port adaptor", + .id = I2C_HW_B_ELV, + .algo_data = &bit_elv_data, + .inc_use = bit_elv_inc_use, + .dec_use = bit_elv_dec_use, }; -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 +175,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 "); 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 Sun Dec 4 15:23:56 2005 @@ -0,0 +1,98 @@ + +/* + * linux/drivers/i2c/i2c-frodo.c + * + * Author: Abraham van der Merwe + * + * 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 +#include +#include +#include +#include +#include +#include + + +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 void frodo_inc_use(struct i2c_adapter *adap) +{ +#ifdef MODULE + MOD_INC_USE_COUNT; +#endif +} + +static void frodo_dec_use(struct i2c_adapter *adap) +{ +#ifdef MODULE + MOD_DEC_USE_COUNT; +#endif +} + +static struct i2c_adapter frodo_ops = { + .name = "Frodo adapter driver", + .id = I2C_HW_B_FRODO, + .algo_data = &bit_frodo_data, + .inc_use = frodo_inc_use, + .dec_use = frodo_dec_use, +}; + +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 "); +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 Feb 18 13:36:32 2004 +++ linux/include/linux/i2c-id.h Sun Dec 4 15:23:56 2005 @@ -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.98 2005/03/15 23:12:17 mds 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,26 @@ #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_SAA7114H 64 /* video decoder */ + #define I2C_DRIVERID_EXP0 0xF0 /* experimental use id's */ #define I2C_DRIVERID_EXP1 0xF1 @@ -102,6 +119,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 +150,30 @@ #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 +#define I2C_DRIVERID_SMSC47B397 1050 +#define I2C_DRIVERID_SMSC47M15X 1051 /* * ---- Adapter types ---------------------------------------------------- @@ -147,14 +190,25 @@ #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_OCP 0x120000 /* IBM or otherwise On-chip I2C algorithm */ +#define I2C_ALGO_BITHS 0x130000 /* enhanced bit style adapters */ +#define I2C_ALGO_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_VIRT 0x180000 /* Virtual bus adapter */ +#define I2C_ALGO_MV64XXX 0x190000 /* Marvell mv64xxx i2c ctlr */ +/* 0x1a0000 reserved for I2C_ALGO_PCA, PCA 9564 style adapters */ +/* 0x1b0000 reserved for I2C_ALGO_AU1550, Au1550 PSC algorithm */ #define I2C_ALGO_EXP 0x800000 /* experimental */ @@ -182,21 +236,47 @@ #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 */ +/* 0x1b reserved for I2C_HW_B_CX2388x, connexant 2388x based tv cards */ /* --- 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 @@ -204,6 +284,9 @@ #define I2C_HW_SGI_VINO 0x00 #define I2C_HW_SGI_MACE 0x01 +/* --- Virtual adapter */ +#define I2C_HW_VIRT 0x00 /* Virtualized adapter */ + /* --- SMBus only adapters */ #define I2C_HW_SMBUS_PIIX4 0x00 #define I2C_HW_SMBUS_ALI15X3 0x01 @@ -213,9 +296,30 @@ #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 + +/* --- Marvell mv64xxx i2c adapter */ +#define I2C_HW_MV64XXX 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 Sun Dec 4 15:23:56 2005 @@ -0,0 +1,298 @@ +/* ------------------------------------------------------------------------- */ +/* 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 */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +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; +} + + +static void pcf_epp_inc_use(struct i2c_adapter *adap) +{ +#ifdef MODULE + MOD_INC_USE_COUNT; +#endif +} + +static void pcf_epp_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_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 = { + .name = "PCF8584 EPP adapter", + .id = I2C_HW_P_LP, + .algo_data = &pcf_epp_data, + .inc_use = pcf_epp_inc_use, + .dec_use = pcf_epp_dec_use, +}; + +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 \n modified by Ryosuke Tajima "); +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 Sun Dec 4 15:23:56 2005 @@ -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 */ + +/* $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 Wed Feb 18 13:36:31 2004 +++ linux/drivers/i2c/i2c-philips-par.c Sun Dec 4 15:23:56 2005 @@ -21,7 +21,7 @@ /* With some changes from Kyösti Mälkki and even Frodo Looijaard */ -/* $Id: i2c-philips-par.c,v 1.18 2000/07/06 19:21:49 frodo Exp $ */ +/* $Id: i2c-philips-par.c,v 1.34 2004/11/25 21:43:45 khali Exp $ */ #include #include @@ -29,14 +29,10 @@ #include #include #include - +#include #include #include -#ifndef __exit -#define __exit __init -#endif - static int type; struct i2c_par @@ -130,24 +126,18 @@ 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) { +#ifdef MODULE MOD_INC_USE_COUNT; +#endif } static void bit_lp_dec_use(struct i2c_adapter *adap) { +#ifdef MODULE MOD_DEC_USE_COUNT; +#endif } /* ------------------------------------------------------------------------ @@ -156,33 +146,29 @@ */ 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, + .name = "Philips Parallel port adapter", + .id = I2C_HW_B_LP, + .inc_use = bit_lp_inc_use, + .dec_use = bit_lp_dec_use, }; static void i2c_parport_attach (struct parport *port) @@ -202,6 +188,7 @@ NULL); if (!adapter->pdev) { printk(KERN_ERR "i2c-philips-par: Unable to register with parport.\n"); + kfree(adapter); return; } @@ -210,8 +197,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 +248,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 +257,7 @@ return 0; } -void __exit i2c_bitlp_exit(void) +static void __exit i2c_bitlp_exit(void) { parport_unregister_driver(&i2c_driver); } @@ -279,14 +270,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 Sun Dec 4 15:23:56 2005 @@ -0,0 +1,183 @@ +/* ------------------------------------------------------------------------- */ +/* 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#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; +} + +static void bit_pport_inc_use(struct i2c_adapter *adap) +{ +#ifdef MODULE + MOD_INC_USE_COUNT; +#endif +} + +static void bit_pport_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_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 = { + .name = "Primitive Parallel port adaptor", + .id = I2C_HW_B_PPORT, + .algo_data = &bit_pport_data, + .inc_use = bit_pport_inc_use, + .dec_use = bit_pport_dec_use, +}; + +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 "); +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 Thu Jan 27 17:57:32 2005 +++ linux/drivers/i2c/i2c-proc.c Sun Dec 4 15:23:56 2005 @@ -23,29 +23,26 @@ This driver puts entries in /proc/sys/dev/sensors for each I2C device */ +#include #include #include #include #include #include #include +#include #include -#include - #include #include +#include -#include - -#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, +static int i2c_parse_reals(int *nrels, char *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, char *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 +#define SENSORS_ENTRY_MAX 24 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 @@ -126,137 +125,93 @@ 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_MODULE when calling. */ int i2c_register_entry(struct i2c_client *client, const char *prefix, - ctl_table * ctl_template, + ctl_table *ctl_template, struct module *controlling_mod) { - int i, res, len, id; - ctl_table *new_table; - char *name; - struct ctl_table_header *new_header; + 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; - if ((res = i2c_create_name(&name, prefix, client->adapter, - client->addr))) return res; + name = generate_name(client, prefix); + if (IS_ERR(name)) + return PTR_ERR(name); - for (id = 0; id < SENSORS_ENTRY_MAX; id++) - if (!i2c_entries[id]) { - break; - } - if (id == SENSORS_ENTRY_MAX) { - kfree(name); - return -ENOMEM; + for (id = 0; id < SENSORS_ENTRY_MAX; id++) { + if (!i2c_entries[id]) + goto free_slot; } - id += 256; - len = 0; + goto out_free_name; + + free_slot: while (ctl_template[len].ctl_name) 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; - } - - i2c_entries[id - 256] = new_header; - - 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; + 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; + hdr->ctl_table->child->child->de->owner = controlling_mod; + + 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]; @@ -287,14 +242,14 @@ if(copy_to_user(buffer, BUF, buflen)) return -EFAULT; curbufsize += buflen; - (char *) buffer += buflen; + buffer += buflen; } *lenp = curbufsize; filp->f_pos += curbufsize; 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) { @@ -318,8 +273,7 @@ sizeof(struct i2c_chips_data))) return -EFAULT; - (char *) oldval += - sizeof(struct i2c_chips_data); + oldval += sizeof(struct i2c_chips_data); nrels++; } oldlen = nrels * sizeof(struct i2c_chips_data); @@ -456,7 +410,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, char *buffer, int bufsize, long *results, int magnitude) { int maxels, min, mag; @@ -470,10 +424,10 @@ /* Skip spaces at the start */ while (bufsize && - !((ret=get_user(nextchar, (char *) buffer))) && + !((ret=get_user(nextchar, buffer))) && isspace((int) nextchar)) { bufsize--; - ((char *) buffer)++; + buffer++; } if (ret) @@ -488,22 +442,22 @@ mag = magnitude; /* Check for a minus */ - if (!((ret=get_user(nextchar, (char *) buffer))) + if (!((ret=get_user(nextchar, buffer))) && (nextchar == '-')) { min = 1; bufsize--; - ((char *) buffer)++; + buffer++; } if (ret) return -EFAULT; /* Digits before a decimal dot */ while (bufsize && - !((ret=get_user(nextchar, (char *) buffer))) && + !((ret=get_user(nextchar, buffer))) && isdigit((int) nextchar)) { res = res * 10 + nextchar - '0'; bufsize--; - ((char *) buffer)++; + buffer++; } if (ret) return -EFAULT; @@ -517,16 +471,16 @@ if (bufsize && (nextchar == '.')) { /* Skip the dot */ bufsize--; - ((char *) buffer)++; + buffer++; /* Read digits while they are significant */ while (bufsize && (mag > 0) && - !((ret=get_user(nextchar, (char *) buffer))) && + !((ret=get_user(nextchar, buffer))) && isdigit((int) nextchar)) { res = res * 10 + nextchar - '0'; mag--; bufsize--; - ((char *) buffer)++; + buffer++; } if (ret) return -EFAULT; @@ -539,10 +493,10 @@ /* Skip everything until we hit whitespace */ while (bufsize && - !((ret=get_user(nextchar, (char *) buffer))) && + !((ret=get_user(nextchar, buffer))) && !isspace((int) nextchar)) { bufsize--; - ((char *) buffer)++; + buffer++; } if (ret) return -EFAULT; @@ -557,7 +511,7 @@ return 0; } -int i2c_write_reals(int nrels, void *buffer, int *bufsize, +static int i2c_write_reals(int nrels, char *buffer, size_t *bufsize, long *results, int magnitude) { #define BUFLEN 20 @@ -571,10 +525,10 @@ mag = magnitude; if (nr != 0) { - if(put_user(' ', (char *) buffer)) + if(put_user(' ', buffer)) return -EFAULT; curbufsize++; - ((char *) buffer)++; + buffer++; } /* Fill BUF with the representation of the next string */ @@ -615,12 +569,12 @@ if(copy_to_user(buffer, BUF, buflen)) return -EFAULT; curbufsize += buflen; - (char *) buffer += buflen; + buffer += buflen; nr++; } if (curbufsize < *bufsize) { - if(put_user('\n', (char *) buffer)) + if(put_user('\n', buffer)) return -EFAULT; curbufsize++; } @@ -646,6 +600,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 +801,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 "); 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 22 08:49:00 2005 +++ linux/include/linux/i2c-proc.h Sun Dec 4 15:23:57 2005 @@ -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 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 -#include #include /* The type of callback functions used in sensors_{proc,sysctl}_real */ @@ -347,6 +343,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 +383,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 +393,6 @@ return value; } -#endif /* def __KERNEL__ */ - /* The maximum length of the prefix */ #define SENSORS_PREFIX_MAX 20 @@ -392,5 +411,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 Sun Dec 4 15:23:57 2005 @@ -0,0 +1,116 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include + + +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 void rpx_inc_use(struct i2c_adapter *adap) +{ +#ifdef MODULE + MOD_INC_USE_COUNT; +#endif +} + +static void rpx_dec_use(struct i2c_adapter *adap) +{ +#ifdef MODULE + MOD_DEC_USE_COUNT; +#endif +} + +static struct i2c_algo_8xx_data rpx_data = { + .setisr = rpx_install_isr +}; + +static struct i2c_adapter rpx_ops = { + .name = "m8xx", + .id = I2C_HW_MPC8XX_EPON, + .algo_data = &rpx_data, + .inc_use = rpx_inc_use, + .dec_use = rpx_dec_use, +}; + +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 "); +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 Wed Feb 18 13:36:31 2004 +++ linux/drivers/i2c/i2c-velleman.c Sun Dec 4 15:23:57 2005 @@ -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.34 2004/11/25 21:43:45 khali Exp $ */ #include #include #include #include -#include /* for 2.0 kernels to get NULL */ -#include /* for 2.0 kernels to get ENODEV */ -#include - +#include +#include #include #include +#include +#include /* for HZ */ /* ----- global defines ----------------------------------------------- */ #define DEB(x) /* should be reasonable open, close &c. */ @@ -90,34 +90,15 @@ 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) -{ + bit_velle_setsda((void*)base,1); + bit_velle_setscl((void*)base,1); return 0; } -static int bit_velle_unreg(struct i2c_client *client) -{ - return 0; -} static void bit_velle_inc_use(struct i2c_adapter *adap) { @@ -139,26 +120,24 @@ */ 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, + .name = "Velleman K8000", + .id = I2C_HW_B_VELLE, + .algo_data = &bit_velle_data, + .inc_use = bit_velle_inc_use, + .dec_use = bit_velle_dec_use, }; -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 +163,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 "); 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 Nov 22 08:49:00 2005 +++ linux/include/linux/i2c.h Sun Dec 4 15:23:57 2005 @@ -23,27 +23,27 @@ /* With some changes from Kyösti Mälkki and Frodo Looijaard */ -/* $Id: i2c.h,v 1.46 2001/08/31 00:04:07 phil Exp $ */ +/* $Id: i2c.h,v 1.94 2005/09/06 19:45:15 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" - -#include /* id values of adapters et. al. */ -#include - - -struct i2c_msg; +#define I2C_DATE "20050906" +#define I2C_VERSION "2.9.2" +/* You can set this to 0 if you patch i2c into your kernel tree + and have no i2c module that have been compiled using a + Linux-2.4-compatible i2c.h header file left. + As a result, you'll get a different code (can't really + say whether it's any better, but it's different). */ +#define I2C_LINUX_2_4_BINARY_COMPATIBILITY 1 -#ifdef __KERNEL__ - -/* --- Includes and compatibility declarations ------------------------ */ - +#include +#include +#include +#include #include -#include +#include /* --- General options ------------------------------------------------ */ @@ -51,6 +51,7 @@ #define I2C_DRIVER_MAX 16 #define I2C_CLIENT_MAX 32 +struct i2c_msg; struct i2c_algorithm; struct i2c_adapter; struct i2c_client; @@ -58,7 +59,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 @@ -111,6 +111,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); @@ -147,14 +149,17 @@ */ int (*command)(struct i2c_client *client,unsigned int cmd, void *arg); - /* These two are mainly used for bookkeeping & dynamic unloading of + /* These two are 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. + * You should use the i2c_{inc,dec}_use_client functions instead of + * calling this function directly. + * Note that most clients won't need to implement these, only those + * which have users inside the kernel (as opposed to only in + * user-space through i2c-proc). */ void (*inc_use)(struct i2c_client *client); void (*dec_use)(struct i2c_client *client); @@ -239,11 +244,16 @@ /* and can be set via the i2c_ioctl call */ /* data fields that are valid for all devices */ - struct semaphore lock; + struct semaphore bus; +#if !I2C_LINUX_2_4_BINARY_COMPATIBILITY + struct semaphore list; +#endif unsigned int flags;/* flags specifying div. data */ struct i2c_client *clients[I2C_CLIENT_MAX]; - int client_count; +#if I2C_LINUX_2_4_BINARY_COMPATIBILITY + int client_count; /* not used anywhere */ +#endif int timeout; int retries; @@ -262,6 +272,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 @@ -300,12 +313,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 @@ -339,6 +346,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); @@ -356,8 +372,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 */ @@ -368,6 +382,11 @@ #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 */ }; @@ -376,7 +395,13 @@ #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 @@ -387,8 +412,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) @@ -400,13 +429,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 @@ -416,8 +460,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 */ @@ -433,6 +478,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: @@ -458,9 +508,7 @@ #define I2C_FUNCS 0x0705 /* Get the adapter functionality */ #define I2C_RDWR 0x0707 /* Combined R/W transfer (one stop only)*/ -#if 0 -#define I2C_ACK_TEST 0x0710 /* See if a slave is at a specific address */ -#endif +#define I2C_PEC 0x0708 /* != 0 for SMBus PEC */ #define I2C_SMBUS 0x0720 /* SMBus-level access */ @@ -473,16 +521,6 @@ #define I2C_MAJOR 89 /* Device major number */ -#ifdef __KERNEL__ - -# ifndef NULL -# define NULL ( (void *) 0 ) -# endif - -# ifndef ENODEV -# include -# 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, \ @@ -544,5 +582,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 */