--- linux-old/Documentation/Configure.help Wed Sep 7 05:46:25 2005 +++ linux/Documentation/Configure.help Wed Sep 7 05:46:48 2005 @@ -19435,6 +19435,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. @@ -19456,6 +19466,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 @@ -19493,6 +19512,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 Wed Sep 7 05:46:48 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 Wed Sep 7 05:46:48 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 Wed Sep 7 05:46:48 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 Wed Sep 7 05:46:49 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 Wed Sep 7 05:46:49 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 Wed Sep 7 05:46:49 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 Wed Sep 7 05:46:49 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 Wed Sep 7 05:46:25 2005 +++ linux/Documentation/i2c/writing-clients Wed Sep 7 05:46:49 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' @@ -380,9 +385,6 @@ For now, you can ignore the `flags' parameter. It is there for future use. - /* Unique ID allocation */ - static int foo_id = 0; - int foo_detect_client(struct i2c_adapter *adapter, int address, unsigned short flags, int kind) { @@ -518,7 +520,6 @@ data->type = kind; /* SENSORS ONLY END */ - new_client->id = foo_id++; /* Automatically unique */ data->valid = 0; /* Only if you use this field */ init_MUTEX(&data->update_lock); /* Only if you use this field */ --- linux-old/drivers/i2c/i2c-adap-ibm_ocp.c Thu Jan 1 00:00:00 1970 +++ linux/drivers/i2c/i2c-adap-ibm_ocp.c Wed Sep 7 05:46:49 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 Wed Sep 7 05:46:50 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 Wed Sep 7 05:46:50 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 Wed Feb 18 13:36:31 2004 +++ linux/drivers/i2c/i2c-algo-bit.c Wed Sep 7 05:46:50 2005 @@ -18,24 +18,22 @@ 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 #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; @@ -43,27 +41,13 @@ #define DEBPROTO(x) if (i2c_debug>=9) { x; } /* debug the protocol by showing transferred bits */ -/* debugging - slow down transfer to have a look at the data .. */ -/* I use this with two leds&resistors, each one connected to sda,scl */ -/* respectively. This makes sure that the algorithm works. Some chips */ -/* might not like this, as they have an internal timeout of some mils */ -/* -#define SLO_IO jif=jiffies;while(time_before_eq(jiffies, jif+i2c_table[minor].veryslow))\ - if (need_resched) schedule(); -*/ - /* ----- global variables --------------------------------------------- */ -#ifdef SLO_IO - int jif; -#endif - /* module parameters: */ static int i2c_debug; static int bit_test; /* see if the line-setting functions work */ -static int bit_scan; /* have a look at what's hanging 'round */ /* --- setting states on the bus with the right timing: --------------- */ @@ -88,9 +72,6 @@ { setscl(adap,0); udelay(adap->udelay); -#ifdef SLO_IO - SLO_IO -#endif } /* @@ -99,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; } @@ -123,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; } @@ -144,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); @@ -178,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); @@ -186,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: @@ -196,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 ") ); @@ -219,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; @@ -232,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); } @@ -242,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); @@ -340,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; @@ -358,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++; @@ -377,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); @@ -395,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 ")); @@ -419,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; @@ -453,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; } @@ -465,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; } @@ -479,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; @@ -496,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; @@ -514,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_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR | - I2C_FUNC_PROTOCOL_MANGLING; + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | + 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, }; /* @@ -545,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) { @@ -565,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 Mon Dec 11 21:15:41 2000 +++ linux/include/linux/i2c-algo-bit.h Wed Sep 7 05:46:50 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 Wed Sep 7 05:46:50 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 Wed Sep 7 05:46:50 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 Wed Feb 18 13:36:31 2004 +++ linux/drivers/i2c/i2c-algo-pcf.c Wed Sep 7 05:46:50 2005 @@ -32,14 +32,11 @@ #include #include #include -#include -#include #include #include - #include #include -#include "i2c-pcf8584.h" + /* ----- global defines ----------------------------------------------- */ #define DEB(x) if (i2c_debug>=1) x @@ -52,7 +49,6 @@ /* module parameters: */ static int i2c_debug=0; -static int pcf_scan=0; /* have a look at what's hanging 'round */ /* --- setting states on the bus with the right timing: --------------- */ @@ -149,8 +145,7 @@ set_pcf(adap, 1, I2C_PCF_PIN); /* check to see S1 now used as R/W ctrl - PCF8584 does that when ESO is zero */ - /* PCF also resets PIN bit */ - if ((temp = get_pcf(adap, 1)) != (0)) { + if (((temp = get_pcf(adap, 1)) & 0x7f) != (0)) { DEB2(printk(KERN_ERR "i2c-algo-pcf.o: PCF detection failed -- can't select S0 (0x%02x).\n", temp)); return -ENXIO; /* definetly not PCF8584 */ } @@ -166,7 +161,7 @@ /* S1=0xA0, next byte in S2 */ set_pcf(adap, 1, I2C_PCF_PIN | I2C_PCF_ES1); /* check to see S2 now selected */ - if ((temp = get_pcf(adap, 1)) != I2C_PCF_ES1) { + if (((temp = get_pcf(adap, 1)) & 0x7f) != I2C_PCF_ES1) { DEB2(printk(KERN_ERR "i2c-algo-pcf.o: PCF detection failed -- can't select S2 (0x%02x).\n", temp)); return -ENXIO; } @@ -427,29 +422,19 @@ return (i); } -static int algo_control(struct i2c_adapter *adapter, - unsigned int cmd, unsigned long arg) -{ - return 0; -} - static u32 pcf_func(struct i2c_adapter *adap) { - return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR | - I2C_FUNC_PROTOCOL_MANGLING; + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | + I2C_FUNC_10BIT_ADDR | I2C_FUNC_PROTOCOL_MANGLING; } /* -----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, }; /* @@ -457,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", @@ -475,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 Mon Dec 11 21:22:34 2000 +++ linux/include/linux/i2c-algo-pcf.h Wed Sep 7 05:46:51 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 Wed Feb 18 13:36:31 2004 +++ linux/drivers/i2c/i2c-core.c Wed Sep 7 05:46:51 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)); @@ -851,7 +814,7 @@ at all */ found = 0; - for (i = 0; !found && (address_data->force[i] != I2C_CLIENT_END); i += 3) { + for (i = 0; !found && (address_data->force[i] != I2C_CLIENT_END); i += 2) { if (((adap_id == address_data->force[i]) || (address_data->force[i] == ANY_I2C_BUS)) && (addr == address_data->force[i+1])) { @@ -901,7 +864,7 @@ if (addr == address_data->normal_i2c[i]) { found = 1; DEB2(printk(KERN_DEBUG "i2c-core.o: found normal i2c entry for adapter %d, " - "addr %02x", adap_id,addr)); + "addr %02x\n", adap_id, 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) { @@ -1098,13 +1216,13 @@ need to use only one message; when reading, we need two. We initialize most things with sane defaults, to keep the code below somewhat simpler. */ - unsigned char msgbuf0[34]; - unsigned char msgbuf1[34]; + unsigned char msgbuf0[I2C_SMBUS_BLOCK_MAX+2]; + unsigned char msgbuf1[I2C_SMBUS_BLOCK_MAX+2]; int num = read_write == I2C_SMBUS_READ?2:1; struct i2c_msg msg[2] = { { addr, flags, 1, msgbuf0 }, { addr, flags | I2C_M_RD, 0, msgbuf1 } }; - int i; + int i, len; msgbuf0[0] = command; switch(size) { @@ -1140,16 +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 @@ pr