Patch 3 is straight diff from linux-2.5.15 and i2c-2.5.3. --- linux/drivers/i2c/i2c-algo-8xx.c.orig 1969-12-31 19:00:00.000000000 -0500 +++ linux/drivers/i2c/i2c-algo-8xx.c 2001-10-30 22:06:31.000000000 -0500 @@ -0,0 +1,575 @@ +/* + * i2c-algo-8xx.c i2x driver algorithms for MPC8XX CPM + * Copyright (c) 1999 Dan Malek (dmalek at jlc.net). + * + * moved into proper i2c interface; separated out platform specific + * parts into i2c-rpx.c + * Brad Parker (brad at heeltoe.com) + */ + +// XXX todo +// timeout sleep? + +/* $Id: i2c-algo-8xx.c,v 1.4 2001/10/31 03:06:31 mds Exp $ */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/delay.h> +#include <linux/slab.h> +#include <linux/version.h> +#include <linux/init.h> +#include <asm/uaccess.h> +#include <linux/ioport.h> +#include <linux/errno.h> +#include <linux/sched.h> + +#include <asm/mpc8xx.h> +#include "../../arch/ppc/8xx_io/commproc.h" + +#include <linux/i2c.h> +#include <linux/i2c-algo-8xx.h> + +#define CPM_MAX_READ 513 + +static wait_queue_head_t iic_wait; +static ushort r_tbase, r_rbase; + +int cpm_scan = 0; +int cpm_debug = 0; + +static void +cpm_iic_interrupt(void *dev_id) +{ + volatile i2c8xx_t *i2c = (i2c8xx_t *)dev_id; + + if (cpm_debug > 1) + printk("cpm_iic_interrupt(dev_id=%p)\n", dev_id); + + /* Chip errata, clear enable. + */ + i2c->i2c_i2mod = 0; + + /* 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_adap) +{ + volatile iic_t *iip = cpm_adap->iip; + volatile i2c8xx_t *i2c = cpm_adap->i2c; + + if (cpm_debug) printk("cpm_iic_init() - iip=%p\n",iip); + + /* 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_adap->dp_addr; + iip->iic_rbase = r_rbase = cpm_adap->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_adap->reloc == 0) { + volatile cpm8xx_t *cp = cpm_adap->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); + } + + /* Select an arbitrary address. Just make sure it is unique. + */ + i2c->i2c_i2add = 0x34; + + /* Make clock run maximum slow. + */ + i2c->i2c_i2brg = 7; + + /* 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_adap->setisr)(CPMVEC_I2C, cpm_iic_interrupt, (void *)i2c); +} + + +static int +cpm_iic_shutdown(struct i2c_algo_8xx_data *cpm_adap) +{ + volatile i2c8xx_t *i2c = cpm_adap->i2c; + + /* Shut down IIC. + */ + i2c->i2c_i2mod = 0; + 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 = 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; +} + +#define BD_SC_NAK ((ushort)0x0004) /* NAK - did not respond */ +#define CPM_CR_CLOSE_RXBD ((ushort)0x0007) + +static void force_close(struct i2c_algo_8xx_data *cpm) +{ + if (cpm->reloc == 0) { + 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); + } +} + + +/* 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; + + 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). + */ + if (cpm->reloc) { + cpm_reset_iic_params(iip); + } + tb = cpm->temp; + tb = (u_char *)(((uint)tb + 15) & ~15); + tb[0] = abyte; /* Device address byte w/rw flag */ + + flush_dcache_range(tb, 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_INTRPT | BD_SC_LAST | + BD_SC_WRAP | BD_IIC_START; + + rbdf->cbd_datlen = 0; + rbdf->cbd_bufaddr = __pa(buf); + rbdf->cbd_sc = BD_SC_EMPTY | BD_SC_WRAP; + + invalidate_dcache_range(buf, buf+count); + + /* Chip bug, set enable here */ + save_flags(flags); cli(); + i2c->i2c_i2cmr = 0x13; /* Enable some interupts */ + i2c->i2c_i2cer = 0xff; + i2c->i2c_i2mod = 1; /* Enable */ + i2c->i2c_i2com = 0x81; /* Start master */ + + /* Wait for IIC transfer */ + interruptible_sleep_on(&iic_wait); + restore_flags(flags); + if (signal_pending(current)) + return -EIO; + + if (cpm_debug) { + printk("tx sc %04x, rx sc %04x\n", + tbdf->cbd_sc, rbdf->cbd_sc); + } + + if (tbdf->cbd_sc & BD_SC_NAK) { + printk("IIC read; no ack\n"); + return 0; + } + + if (rbdf->cbd_sc & BD_SC_EMPTY) { + printk("IIC read; complete but rbuf empty\n"); + force_close(cpm); + printk("tx sc %04x, rx sc %04x\n", + tbdf->cbd_sc, rbdf->cbd_sc); + } + + if (cpm_debug) printk("read %d bytes\n", rbdf->cbd_datlen); + + if (rbdf->cbd_datlen < count) { + printk("IIC read; short, wanted %d got %d\n", + count, rbdf->cbd_datlen); + return 0; + } + + + invalidate_dcache_range(buf, buf+count); + + 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; + + /* 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(tb, tb+1); + flush_dcache_range(buf, 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; + + /* Chip bug, set enable here */ + save_flags(flags); cli(); + i2c->i2c_i2cmr = 0x13; /* Enable some interupts */ + i2c->i2c_i2cer = 0xff; + i2c->i2c_i2mod = 1; /* Enable */ + i2c->i2c_i2com = 0x81; /* Start master */ + + /* Wait for IIC transfer */ + interruptible_sleep_on(&iic_wait); + restore_flags(flags); + if (signal_pending(current)) + return -EIO; + + 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) { + printk("IIC write; no ack\n"); + return 0; + } + + if (tbdf->cbd_sc & BD_SC_READY) { + 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; + + 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(tb, tb+1); + + tbdf->cbd_bufaddr = __pa(tb); + tbdf->cbd_datlen = len; + tbdf->cbd_sc = + BD_SC_READY | BD_SC_INTRPT | 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; + + save_flags(flags); cli(); + i2c->i2c_i2cmr = 0x13; /* Enable some interupts */ + i2c->i2c_i2cer = 0xff; + i2c->i2c_i2mod = 1; /* Enable */ + i2c->i2c_i2com = 0x81; /* Start master */ + + if (cpm_debug > 1) printk("about to sleep\n"); + + /* wait for IIC transfer */ + interruptible_sleep_on(&iic_wait); + restore_flags(flags); + if (signal_pending(current)) + 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 *i2c_adap, + struct i2c_msg msgs[], + int num) +{ + struct i2c_algo_8xx_data *adap = i2c_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", + i, pmsg->addr, pmsg->flags, pmsg->len); + + 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(adap, 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(adap, 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 int algo_control(struct i2c_adapter *adapter, + unsigned int cmd, unsigned long arg) +{ + return 0; +} + +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 = { + "MPC8xx CPM algorithm", + I2C_ALGO_MPC8XX, + cpm_xfer, + NULL, + NULL, /* slave_xmit */ + NULL, /* slave_recv */ + algo_control, /* ioctl */ + cpm_func, /* functionality */ +}; + +/* + * 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 = 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; + +#ifdef MODULE + MOD_INC_USE_COUNT; +#endif + + i2c_add_adapter(adap); + cpm_iic_init(cpm_adap); + + /* scan bus */ + if (cpm_scan) { + printk(KERN_INFO " i2c-algo-8xx.o: scanning bus %s...\n", + adap->name); + for (i = 0; i < 128; i++) { + if (cpm_iic_tryaddress(cpm_adap, i)) { + printk("(%02x)",i<<1); + } + } + printk("\n"); + } + return 0; +} + + +int i2c_8xx_del_bus(struct i2c_adapter *adap) +{ + int res; + struct i2c_algo_8xx_data *cpm_adap = adap->algo_data; + + cpm_iic_shutdown(cpm_adap); + + if ((res = i2c_del_adapter(adap)) < 0) + return res; + + printk("i2c-algo-8xx.o: adapter unregistered: %s\n",adap->name); + +#ifdef MODULE + MOD_DEC_USE_COUNT; +#endif + return 0; +} + +EXPORT_SYMBOL(i2c_8xx_add_bus); +EXPORT_SYMBOL(i2c_8xx_del_bus); + +int __init i2c_algo_8xx_init (void) +{ + printk("i2c-algo-8xx.o: i2c mpc8xx algorithm module version %s (%s)\n", I2C_VERSION, I2C_DATE); + return 0; +} + + +#ifdef MODULE +MODULE_AUTHOR("Brad Parker <brad at heeltoe.com>"); +MODULE_DESCRIPTION("I2C-Bus MPC8XX algorithm"); + +int init_module(void) +{ + return i2c_algo_8xx_init(); +} + +void cleanup_module(void) +{ +} +#endif --- /dev/null 1994-07-17 19:46:18.000000000 -0400 +++ linux/include/linux/i2c-algo-8xx.h 2001-05-14 22:14:58.000000000 -0400 @@ -0,0 +1,29 @@ +/* ------------------------------------------------------------------------- */ +/* i2c-algo-8xx.h i2c driver algorithms for MPX8XX CPM */ +/* ------------------------------------------------------------------------- */ + +/* $Id: i2c-algo-8xx.h,v 1.1 2001/05/15 02:14:58 mds Exp $ */ + +#ifndef I2C_ALGO_8XX_H +#define I2C_ALGO_8XX_H 1 + +#include <linux/i2c.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)(int, void (*)(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 /* I2C_ALGO_8XX_H */ --- linux/drivers/i2c/i2c-algo-bit.c.orig 2002-05-09 18:21:26.000000000 -0400 +++ linux/drivers/i2c/i2c-algo-bit.c 2002-05-14 17:58:35.000000000 -0400 @@ -21,7 +21,7 @@ /* With some changes from Ky?sti M?lkki <kmalkki at cc.hut.fi> and even Frodo Looijaard <frodol at dds.nl> */ -/* $Id: i2c-algo-bit.c,v 1.30 2001/07/29 02:44:25 mds Exp $ */ +/* $Id: i2c-algo-bit.c,v 1.34 2001/11/19 18:45:02 mds Exp $ */ #include <linux/kernel.h> #include <linux/module.h> @@ -33,7 +33,6 @@ #include <linux/ioport.h> #include <linux/errno.h> #include <linux/sched.h> - #include <linux/i2c.h> #include <linux/i2c-algo-bit.h> @@ -49,8 +48,8 @@ /* 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))\ - cond_resched(); +#define SLO_IO jif=jiffies;while(jiffies<=jif+i2c_table[minor].veryslow)\ + if (need_resched) schedule(); */ @@ -117,12 +116,13 @@ * while they are processing data internally. */ setscl(adap,1); - if (time_after_eq(jiffies, start+adap->timeout)) { + if (start+adap->timeout <= jiffies) { return -ETIMEDOUT; } - cond_resched(); + if (current->need_resched) + schedule(); } - DEBSTAT(printk("needed %ld jiffies\n", jiffies-start)); + DEBSTAT(printk(KERN_DEBUG "needed %ld jiffies\n", jiffies-start)); #ifdef SLO_IO SLO_IO #endif @@ -178,12 +178,12 @@ struct i2c_algo_bit_data *adap = i2c_adap->algo_data; /* assert: scl is low */ - DEB2(printk(" i2c_outb:%2.2X\n",c&0xff)); + DEB2(printk(KERN_DEBUG " i2c_outb:%2.2X\n",c&0xff)); for ( i=7 ; i>=0 ; i-- ) { sb = c & ( 1 << i ); setsda(adap,sb); udelay(adap->udelay); - DEBPROTO(printk("%d",sb!=0)); + DEBPROTO(printk(KERN_DEBUG "%d",sb!=0)); if (sclhi(adap)<0) { /* timed out */ sdahi(adap); /* we don't want to block the net */ return -ETIMEDOUT; @@ -200,10 +200,10 @@ }; /* read ack: SDA should be pulled down by slave */ ack=getsda(adap); /* ack: sda is pulled low ->success. */ - DEB2(printk(" i2c_outb: getsda() = 0x%2.2x\n", ~ack )); + DEB2(printk(KERN_DEBUG " i2c_outb: getsda() = 0x%2.2x\n", ~ack )); - DEBPROTO( printk("[%2.2x]",c&0xff) ); - DEBPROTO(if (0==ack){ printk(" A ");} else printk(" NA ") ); + DEBPROTO( printk(KERN_DEBUG "[%2.2x]",c&0xff) ); + DEBPROTO(if (0==ack){ printk(KERN_DEBUG " A ");} else printk(KERN_DEBUG " NA ") ); scllo(adap); return 0==ack; /* return 1 if device acked */ /* assert: scl is low (sda undef) */ @@ -219,7 +219,7 @@ struct i2c_algo_bit_data *adap = i2c_adap->algo_data; /* assert: scl is low */ - DEB2(printk("i2c_inb.\n")); + DEB2(printk(KERN_DEBUG "i2c_inb.\n")); sdahi(adap); for (i=0;i<8;i++) { @@ -232,7 +232,7 @@ scllo(adap); } /* assert: scl is low */ - DEBPROTO(printk(" %2.2x", indata & 0xff)); + DEBPROTO(printk(KERN_DEBUG " %2.2x", indata & 0xff)); return (int) (indata & 0xff); } @@ -244,69 +244,69 @@ int scl,sda; sda=getsda(adap); if (adap->getscl==NULL) { - printk("i2c-algo-bit.o: Warning: Adapter can't read from clock line - skipping test.\n"); + printk(KERN_WARNING "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", + printk(KERN_INFO "i2c-algo-bit.o: Adapter: %s scl: %d sda: %d -- testing...\n", name,getscl(adap),getsda(adap)); if (!scl || !sda ) { - printk("i2c-algo-bit.o: %s seems to be busy.\n",name); + printk(KERN_INFO " 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), + printk(KERN_DEBUG "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); + printk(KERN_WARNING "i2c-algo-bit.o: %s SDA stuck high!\n",name); sdahi(adap); goto bailout; } if ( 0 == getscl(adap) ) { - printk("i2c-algo-bit.o: %s SCL unexpected low while pulling SDA low!\n", + printk(KERN_WARNING "i2c-algo-bit.o: %s SCL unexpected low while pulling SDA low!\n", name); goto bailout; } sdahi(adap); - printk("i2c-algo-bit.o:2 scl: %d sda: %d \n",getscl(adap), + printk(KERN_DEBUG "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); + printk(KERN_WARNING "i2c-algo-bit.o: %s SDA stuck low!\n",name); sdahi(adap); goto bailout; } if ( 0 == getscl(adap) ) { - printk("i2c-algo-bit.o: %s SCL unexpected low while SDA high!\n", + printk(KERN_WARNING "i2c-algo-bit.o: %s SCL unexpected low while SDA high!\n", name); goto bailout; } scllo(adap); - printk("i2c-algo-bit.o:3 scl: %d sda: %d \n",getscl(adap), + printk(KERN_DEBUG "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); + printk(KERN_WARNING "i2c-algo-bit.o: %s SCL stuck high!\n",name); sclhi(adap); goto bailout; } if ( 0 == getsda(adap) ) { - printk("i2c-algo-bit.o: %s SDA unexpected low while pulling SCL low!\n", + printk(KERN_WARNING "i2c-algo-bit.o: %s SDA unexpected low while pulling SCL low!\n", name); goto bailout; } sclhi(adap); - printk("i2c-algo-bit.o:4 scl: %d sda: %d \n",getscl(adap), + printk(KERN_DEBUG "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); + printk(KERN_WARNING "i2c-algo-bit.o: %s SCL stuck low!\n",name); sclhi(adap); goto bailout; } if ( 0 == getsda(adap) ) { - printk("i2c-algo-bit.o: %s SDA unexpected low while SCL high!\n", + printk(KERN_WARNING "i2c-algo-bit.o: %s SDA unexpected low while SCL high!\n", name); 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,7 +340,7 @@ i2c_start(adap); udelay(adap->udelay); } - DEB2(if (i) printk("i2c-algo-bit.o: needed %d retries for %d\n", + DEB2(if (i) printk(KERN_DEBUG "i2c-algo-bit.o: needed %d retries for %d\n", i,addr)); return ret; } @@ -355,7 +355,7 @@ while (count > 0) { c = *temp; - DEB2(printk("i2c-algo-bit.o: %s i2c_write: writing %2.2X\n", + DEB2(printk(KERN_DEBUG "i2c-algo-bit.o: %s i2c_write: writing %2.2X\n", i2c_adap->name, c&0xff)); retval = i2c_outb(i2c_adap,c); if (retval>0) { @@ -363,7 +363,7 @@ temp++; wrcount++; } else { /* arbitration or no acknowledge */ - printk("i2c-algo-bit.o: %s i2c_write: error - bailout.\n", + printk(KERN_ERR "i2c-algo-bit.o: %s i2c_write: error - bailout.\n", i2c_adap->name); i2c_stop(adap); return (retval<0)? retval : -EFAULT; @@ -391,7 +391,7 @@ *temp = inval; rdcount++; } else { /* read timed out */ - printk("i2c-algo-bit.o: i2c_read: i2c_inb timed out.\n"); + printk(KERN_ERR "i2c-algo-bit.o: i2c_read: i2c_inb timed out.\n"); break; } @@ -404,7 +404,7 @@ } if (sclhi(adap)<0) { /* timeout */ sdahi(adap); - printk("i2c-algo-bit.o: i2c_read: Timeout at ack\n"); + printk(KERN_ERR "i2c-algo-bit.o: i2c_read: Timeout at ack\n"); return -ETIMEDOUT; }; scllo(adap); @@ -434,18 +434,18 @@ if ( (flags & I2C_M_TEN) ) { /* a ten bit address */ addr = 0xf0 | (( msg->addr >> 7) & 0x03); - DEB2(printk("addr0: %d\n",addr)); + DEB2(printk(KERN_DEBUG "addr0: %d\n",addr)); /* try extended address code...*/ ret = try_address(i2c_adap, addr, retries); if (ret!=1) { - printk("died at extended address code.\n"); + 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) { /* the chip did not ack / xmission error occurred */ - printk("died at 2nd address code.\n"); + printk(KERN_ERR "died at 2nd address code.\n"); return -EREMOTEIO; } if ( flags & I2C_M_RD ) { @@ -454,7 +454,7 @@ addr |= 0x01; ret = try_address(i2c_adap, addr, retries); if (ret!=1) { - printk("died at extended address code.\n"); + printk(KERN_ERR "died at extended address code.\n"); return -EREMOTEIO; } } @@ -489,7 +489,7 @@ } ret = bit_doAddress(i2c_adap,pmsg,i2c_adap->retries); if (ret != 0) { - DEB2(printk("i2c-algo-bit.o: NAK from device adr %#2x msg #%d\n" + DEB2(printk(KERN_DEBUG "i2c-algo-bit.o: NAK from device adr %#2x msg #%d\n" ,msgs[i].addr,i)); return (ret<0) ? ret : -EREMOTEIO; } @@ -497,14 +497,14 @@ if (pmsg->flags & I2C_M_RD ) { /* read bytes into buffer*/ ret = readbytes(i2c_adap,pmsg->buf,pmsg->len); - DEB2(printk("i2c-algo-bit.o: read %d bytes.\n",ret)); + 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); - DEB2(printk("i2c-algo-bit.o: wrote %d bytes.\n",ret)); + DEB2(printk(KERN_DEBUG "i2c-algo-bit.o: wrote %d bytes.\n",ret)); if (ret < pmsg->len ) { return (ret<0) ? ret : -EREMOTEIO; } @@ -554,7 +554,7 @@ return -ENODEV; } - DEB2(printk("i2c-algo-bit.o: hw routines for %s registered.\n", + DEB2(printk(KERN_DEBUG "i2c-algo-bit.o: hw routines for %s registered.\n", adap->name)); /* register new adapter to i2c module... */ @@ -598,7 +598,7 @@ if ((res = i2c_del_adapter(adap)) < 0) return res; - DEB2(printk("i2c-algo-bit.o: adapter unregistered: %s\n",adap->name)); + DEB2(printk(KERN_DEBUG "i2c-algo-bit.o: adapter unregistered: %s\n",adap->name)); #ifdef MODULE MOD_DEC_USE_COUNT; @@ -608,7 +608,7 @@ int __init i2c_algo_bit_init (void) { - printk("i2c-algo-bit.o: i2c bit algorithm module\n"); + printk(KERN_INFO "i2c-algo-bit.o: i2c bit algorithm module version %s (%s)\n", I2C_VERSION, I2C_DATE); return 0; } @@ -620,7 +620,9 @@ #ifdef MODULE MODULE_AUTHOR("Simon G. Vogl <simon at tk.uni-linz.ac.at>"); MODULE_DESCRIPTION("I2C-Bus bit-banging algorithm"); +#ifdef MODULE_LICENSE MODULE_LICENSE("GPL"); +#endif MODULE_PARM(bit_test, "i"); MODULE_PARM(bit_scan, "i"); --- linux/drivers/i2c/i2c-algo-pcf.c.orig 2002-05-09 18:25:27.000000000 -0400 +++ linux/drivers/i2c/i2c-algo-pcf.c 2002-05-14 18:04:41.000000000 -0400 @@ -37,10 +37,9 @@ #include <linux/ioport.h> #include <linux/errno.h> #include <linux/sched.h> - #include <linux/i2c.h> #include <linux/i2c-algo-pcf.h> -#include "i2c-pcf8584.h" +#include <linux/i2c-pcf8584.h> /* ----- global defines ----------------------------------------------- */ #define DEB(x) if (i2c_debug>=1) x @@ -99,7 +98,7 @@ } #endif if (timeout <= 0) { - printk("Timeout waiting for Bus Busy\n"); + printk(KERN_ERR "Timeout waiting for Bus Busy\n"); } return (timeout<=0); @@ -144,15 +143,14 @@ { unsigned char temp; - DEB3(printk("i2c-algo-pcf.o: PCF state 0x%02x\n", get_pcf(adap, 1))); + DEB3(printk(KERN_DEBUG "i2c-algo-pcf.o: PCF state 0x%02x\n", get_pcf(adap, 1))); /* S1=0x80: S0 selected, serial interface off */ 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)) { - DEB2(printk("i2c-algo-pcf.o: PCF detection failed -- can't select S0 (0x%02x).\n", temp)); + 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 */ } @@ -160,15 +158,15 @@ i2c_outb(adap, get_own(adap)); /* check it's realy writen */ if ((temp = i2c_inb(adap)) != get_own(adap)) { - DEB2(printk("i2c-algo-pcf.o: PCF detection failed -- can't set S0 (0x%02x).\n", temp)); + DEB2(printk(KERN_ERR "i2c-algo-pcf.o: PCF detection failed -- can't set S0 (0x%02x).\n", temp)); return -ENXIO; } /* 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) { - DEB2(printk("i2c-algo-pcf.o: PCF detection failed -- can't select S2 (0x%02x).\n", temp)); + 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; } @@ -176,7 +174,7 @@ i2c_outb(adap, get_clock(adap)); /* check it's realy writen, the only 5 lowest bits does matter */ if (((temp = i2c_inb(adap)) & 0x1f) != get_clock(adap)) { - DEB2(printk("i2c-algo-pcf.o: PCF detection failed -- can't set S2 (0x%02x).\n", temp)); + DEB2(printk(KERN_ERR "i2c-algo-pcf.o: PCF detection failed -- can't set S2 (0x%02x).\n", temp)); return -ENXIO; } @@ -185,11 +183,11 @@ /* check to see PCF is realy idled and we can access status register */ if ((temp = get_pcf(adap, 1)) != (I2C_PCF_PIN | I2C_PCF_BB)) { - DEB2(printk("i2c-algo-pcf.o: PCF detection failed -- can't select S1` (0x%02x).\n", temp)); + DEB2(printk(KERN_ERR "i2c-algo-pcf.o: PCF detection failed -- can't select S1` (0x%02x).\n", temp)); return -ENXIO; } - printk("i2c-algo-pcf.o: deteted and initialized PCF8584.\n"); + printk(KERN_DEBUG "i2c-algo-pcf.o: deteted and initialized PCF8584.\n"); return 0; } @@ -215,7 +213,7 @@ i2c_stop(adap); udelay(adap->udelay); } - DEB2(if (i) printk("i2c-algo-pcf.o: needed %d retries for %d\n",i, + DEB2(if (i) printk(KERN_DEBUG "i2c-algo-pcf.o: needed %d retries for %d\n",i, addr)); return ret; } @@ -228,20 +226,20 @@ int wrcount, status, timeout; for (wrcount=0; wrcount<count; ++wrcount) { - DEB2(printk("i2c-algo-pcf.o: %s i2c_write: writing %2.2X\n", + DEB2(printk(KERN_DEBUG "i2c-algo-pcf.o: %s i2c_write: writing %2.2X\n", i2c_adap->name, buf[wrcount]&0xff)); i2c_outb(adap, buf[wrcount]); timeout = wait_for_pin(adap, &status); if (timeout) { i2c_stop(adap); - printk("i2c-algo-pcf.o: %s i2c_write: " + printk(KERN_ERR "i2c-algo-pcf.o: %s i2c_write: " "error - timeout.\n", i2c_adap->name); return -EREMOTEIO; /* got a better one ?? */ } #ifndef STUB_I2C if (status & I2C_PCF_LRB) { i2c_stop(adap); - printk("i2c-algo-pcf.o: %s i2c_write: " + printk(KERN_ERR "i2c-algo-pcf.o: %s i2c_write: " "error - no ack.\n", i2c_adap->name); return -EREMOTEIO; /* got a better one ?? */ } @@ -269,14 +267,14 @@ if (wait_for_pin(adap, &status)) { i2c_stop(adap); - printk("i2c-algo-pcf.o: pcf_readbytes timed out.\n"); + printk(KERN_ERR "i2c-algo-pcf.o: pcf_readbytes timed out.\n"); return (-1); } #ifndef STUB_I2C if ((status & I2C_PCF_LRB) && (i != count)) { i2c_stop(adap); - printk("i2c-algo-pcf.o: i2c_read: i2c_inb, No ack.\n"); + printk(KERN_ERR "i2c-algo-pcf.o: i2c_read: i2c_inb, No ack.\n"); return (-1); } #endif @@ -312,18 +310,18 @@ if ( (flags & I2C_M_TEN) ) { /* a ten bit address */ addr = 0xf0 | (( msg->addr >> 7) & 0x03); - DEB2(printk("addr0: %d\n",addr)); + DEB2(printk(KERN_DEBUG "addr0: %d\n",addr)); /* try extended address code...*/ ret = try_address(adap, addr, retries); if (ret!=1) { - printk("died at extended address code.\n"); + printk(KERN_ERR "died at extended address code.\n"); return -EREMOTEIO; } /* the remaining 8 bit address */ i2c_outb(adap,msg->addr & 0x7f); /* Status check comes here */ if (ret != 1) { - printk("died at 2nd address code.\n"); + printk(KERN_ERR "died at 2nd address code.\n"); return -EREMOTEIO; } if ( flags & I2C_M_RD ) { @@ -332,7 +330,7 @@ addr |= 0x01; ret = try_address(adap, addr, retries); if (ret!=1) { - printk("died at extended address code.\n"); + printk(KERN_ERR "died at extended address code.\n"); return -EREMOTEIO; } } @@ -360,7 +358,7 @@ /* Check for bus busy */ timeout = wait_for_bb(adap); if (timeout) { - DEB2(printk("i2c-algo-pcf.o: " + DEB2(printk(KERN_ERR "i2c-algo-pcf.o: " "Timeout waiting for BB in pcf_xfer\n");) return -EIO; } @@ -368,7 +366,7 @@ for (i = 0;ret >= 0 && i < num; i++) { pmsg = &msgs[i]; - DEB2(printk("i2c-algo-pcf.o: Doing %s %d bytes to 0x%02x - %d of %d messages\n", + DEB2(printk(KERN_DEBUG "i2c-algo-pcf.o: Doing %s %d bytes to 0x%02x - %d of %d messages\n", pmsg->flags & I2C_M_RD ? "read" : "write", pmsg->len, pmsg->addr, i + 1, num);) @@ -383,7 +381,7 @@ timeout = wait_for_pin(adap, &status); if (timeout) { i2c_stop(adap); - DEB2(printk("i2c-algo-pcf.o: Timeout waiting " + DEB2(printk(KERN_ERR "i2c-algo-pcf.o: Timeout waiting " "for PIN(1) in pcf_xfer\n");) return (-EREMOTEIO); } @@ -392,12 +390,12 @@ /* Check LRB (last rcvd bit - slave ack) */ if (status & I2C_PCF_LRB) { i2c_stop(adap); - DEB2(printk("i2c-algo-pcf.o: No LRB(1) in pcf_xfer\n");) + DEB2(printk(KERN_ERR "i2c-algo-pcf.o: No LRB(1) in pcf_xfer\n");) return (-EREMOTEIO); } #endif - DEB3(printk("i2c-algo-pcf.o: Msg %d, addr=0x%x, flags=0x%x, len=%d\n", + DEB3(printk(KERN_DEBUG "i2c-algo-pcf.o: Msg %d, addr=0x%x, flags=0x%x, len=%d\n", i, msgs[i].addr, msgs[i].flags, msgs[i].len);) /* Read */ @@ -407,20 +405,20 @@ (i + 1 == num)); if (ret != pmsg->len) { - DEB2(printk("i2c-algo-pcf.o: fail: " + DEB2(printk(KERN_DEBUG "i2c-algo-pcf.o: fail: " "only read %d bytes.\n",ret)); } else { - DEB2(printk("i2c-algo-pcf.o: read %d bytes.\n",ret)); + DEB2(printk(KERN_DEBUG "i2c-algo-pcf.o: read %d bytes.\n",ret)); } } else { /* Write */ ret = pcf_sendbytes(i2c_adap, pmsg->buf, pmsg->len, (i + 1 == num)); if (ret != pmsg->len) { - DEB2(printk("i2c-algo-pcf.o: fail: " + DEB2(printk(KERN_DEBUG "i2c-algo-pcf.o: fail: " "only wrote %d bytes.\n",ret)); } else { - DEB2(printk("i2c-algo-pcf.o: wrote %d bytes.\n",ret)); + DEB2(printk(KERN_DEBUG "i2c-algo-pcf.o: wrote %d bytes.\n",ret)); } } } @@ -461,7 +459,7 @@ int i, status; struct i2c_algo_pcf_data *pcf_adap = adap->algo_data; - DEB2(printk("i2c-algo-pcf.o: hw routines for %s registered.\n", + DEB2(printk(KERN_DEBUG "i2c-algo-pcf.o: hw routines for %s registered.\n", adap->name)); /* register new adapter to i2c module... */ @@ -514,7 +512,7 @@ int res; if ((res = i2c_del_adapter(adap)) < 0) return res; - DEB2(printk("i2c-algo-pcf.o: adapter unregistered: %s\n",adap->name)); + DEB2(printk(KERN_DEBUG "i2c-algo-pcf.o: adapter unregistered: %s\n",adap->name)); #ifdef MODULE MOD_DEC_USE_COUNT; @@ -524,7 +522,7 @@ int __init i2c_algo_pcf_init (void) { - printk("i2c-algo-pcf.o: i2c pcf8584 algorithm module\n"); + printk(KERN_INFO "i2c-algo-pcf.o: i2c pcf8584 algorithm module version %s (%s)\n", I2C_VERSION, I2C_DATE); return 0; } @@ -535,7 +533,9 @@ #ifdef MODULE MODULE_AUTHOR("Hans Berglund <hb at spacetec.no>"); MODULE_DESCRIPTION("I2C-Bus PCF8584 algorithm"); +#ifdef MODULE_LICENSE MODULE_LICENSE("GPL"); +#endif MODULE_PARM(pcf_scan, "i"); MODULE_PARM(i2c_debug,"i"); --- linux/drivers/i2c/i2c-algo-ppc405.c.orig 1969-12-31 19:00:00.000000000 -0500 +++ linux/drivers/i2c/i2c-algo-ppc405.c 2002-05-14 18:04:54.000000000 -0400 @@ -0,0 +1,1040 @@ +/* + ------------------------------------------------------------------------- + i2c-algo-ppc405.c i2c driver algorithms for IBM PPC 405 adapters + ------------------------------------------------------------------------- + + Ian DaSilva, MontaVista Software, Inc. + idasilva at mvista.com or source at mvista.com + + Copyright 2000 MontaVista Software Inc. + + Changes made to support the IIC peripheral on the IBM PPC 405 + + + --------------------------------------------------------------------------- + This file was highly leveraged from i2c-algo-pcf.c, which was created + by Simon G. Vogl and Hans Berglund: + + + Copyright (C) 1995-1997 Simon G. Vogl + 1998-2000 Hans Berglund + + With some changes from Ky?sti M?lkki <kmalkki at cc.hut.fi> and + Frodo Looijaard <frodol at dds.nl> ,and also from Martin Bailey + <mbailey at littlefeet-inc.com> + + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + --------------------------------------------------------------------------- +*/ + + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/delay.h> +#include <linux/slab.h> +#include <linux/version.h> +#include <linux/init.h> +#include <asm/uaccess.h> +#include <linux/ioport.h> +#include <linux/errno.h> +#include <linux/sched.h> +#include <linux/i2c.h> +#include <linux/i2c-algo-ppc405.h> +#include <linux/i2c-ppc405.h> + +#ifdef MODULE_LICENSE +MODULE_LICENSE("GPL"); +#endif + +/* ----- 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 + +/* 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(jiffies<=jif+i2c_table[minor].veryslow)\ + if (need_resched) schedule(); +*/ + + +/* ----- global variables --------------------------------------------- */ + +#ifdef SLO_IO + int jif; +#endif + +/* module parameters: + */ +static int i2c_debug=1; +//static int iic_test=0; /* see if the line-setting functions work */ +static int iic_scan=0; /* have a look at what's hanging 'round */ + +/* --- setting states on the bus with the right timing: --------------- */ + +#define iic_outb(adap, reg, val) adap->setiic(adap->data, reg, val) +#define iic_inb(adap, reg) adap->getiic(adap->data, 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 + +/* --- other auxiliary functions -------------------------------------- */ + + +#if 0 +//static int wait_for_bb(struct i2c_algo_iic_data *adap) { +// +// int timeout = DEF_TIMEOUT; +// int status; +// +// status = iic_inb(adap, 1); +//#ifndef STUB_I2C +// while (timeout-- && !(status & I2C_PCF_BB)) { +// udelay(1000); /* How much is this? */ +// status = iic_inb(adap, 1); +// } +//#endif +// if (timeout<=0) +// printk(KERN_ERR "Timeout waiting for Bus Busy\n"); +// /* +// iic_outb(adap, 1, I2C_PCF_STOP); +// */ +// return(timeout<=0); +//} +#endif + +// +// 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) +{ + + // printk("iic_init: at the start of iic_init\n"); + + /* Clear master low master address */ + iic_outb(adap,PPC405GP_IICO_BASE+IICO_LMADR, 0); + + /* Clear high master address */ + iic_outb(adap,PPC405GP_IICO_BASE+IICO_HMADR, 0); + + /* Clear low slave address */ + iic_outb(adap,PPC405GP_IICO_BASE+IICO_LSADR, 0); + + /* Clear high slave address */ + iic_outb(adap,PPC405GP_IICO_BASE+IICO_HSADR, 0); + + /* Clear status */ + iic_outb(adap,PPC405GP_IICO_BASE+IICO_STS, 0x0a); + + /* Clear extended status */ + iic_outb(adap,PPC405GP_IICO_BASE+IICO_EXTSTS, 0x8f); + + /* Set clock division */ + iic_outb(adap,PPC405GP_IICO_BASE+IICO_CLKDIV, 0x04); + + /* Enable interrupts on Requested Master Transfer Complete */ + iic_outb(adap,PPC405GP_IICO_BASE+IICO_INTRMSK, 0x01); + + /* Clear transfer count */ + iic_outb(adap,PPC405GP_IICO_BASE+IICO_XFRCNT, 0x0); + + /* Clear extended control and status */ + iic_outb(adap,PPC405GP_IICO_BASE+IICO_XTCNTLSS, 0xf0); + + /* Set mode control (flush master data buf, enable hold SCL, exit */ + /* unknown state. */ + iic_outb(adap,PPC405GP_IICO_BASE+IICO_MDCNTL, 0x47); + + /* Clear control register */ + iic_outb(adap,PPC405GP_IICO_BASE+IICO_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; + + *status = iic_inb(adap, PPC405GP_IICO_BASE + IICO_STS); + //printk("wait_for_pin: status = %x\n", *status); +#ifndef STUB_I2C + + while (timeout-- && (*status & 0x01)) { + //printk("wait_for_pin: timeout=%d, status=%x\n", timeout, *status); + //printk("wait_for_pin: calling waitforpin\n"); + adap->waitforpin(); + //printk("wait_for_pin: returning from waitforpin\n"); + *status = iic_inb(adap, PPC405GP_IICO_BASE + IICO_STS); + } +#endif + //printk("wait_for_pin: returning from wait_for_pin\n"); + if (timeout <= 0) { + /* Issue stop signal on the bus, and force an interrupt */ + retval = iic_inb(adap, PPC405GP_IICO_BASE+IICO_CNTL); + iic_outb(adap, PPC405GP_IICO_BASE+IICO_CNTL, retval | 0x80); + /* Clear status register */ + iic_outb(adap, PPC405GP_IICO_BASE+IICO_STS, 0x0a); + /* Exit unknown bus state */ + retval = iic_inb(adap, PPC405GP_IICO_BASE+IICO_MDCNTL); + iic_outb(adap, PPC405GP_IICO_BASE+IICO_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, PPC405GP_IICO_BASE+IICO_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, PPC405GP_IICO_BASE+IICO_XTCNTLSS, 0x01); + udelay(500); + iic_init(adap); + /* Is the pending transfer bit in the sts reg finally cleared? */ + retval = iic_inb(adap, PPC405GP_IICO_BASE+IICO_STS); + retval = retval & 0x01; + if(retval) { + printk("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, PPC405GP_IICO_BASE+IICO_INTRMSK, 0x01); + } + return(-1); + } + else + return(0); +} + + +// +// Description: Sanity check for the adapter hardware - check the reaction of +// the bus lines only if it seems to be idle. +// +#if 0 +static int test_bus(struct i2c_algo_iic_data *adap, char *name) { + int scl,sda; + sda=getsda(adap); + if (adap->getscl==NULL) { + printk("test_bus: Warning: Adapter can't read from clock line - skipping test.\n"); + return 0; + } + scl=getscl(adap); + printk("test_bus: Adapter: %s scl: %d sda: %d -- testing...\n", + name,getscl(adap),getsda(adap)); + if (!scl || !sda ) { + printk("test_bus: %s seems to be busy.\n",adap->name); + goto bailout; + } + sdalo(adap); + printk("test_bus:1 scl: %d sda: %d \n",getscl(adap), + getsda(adap)); + if ( 0 != getsda(adap) ) { + printk("test_bus: %s SDA stuck high!\n",name); + sdahi(adap); + goto bailout; + } + if ( 0 == getscl(adap) ) { + printk("test_bus: %s SCL unexpected low while pulling SDA low!\n", + name); + goto bailout; + } + sdahi(adap); + printk("test_bus:2 scl: %d sda: %d \n",getscl(adap), + getsda(adap)); + if ( 0 == getsda(adap) ) { + printk("test_bus: %s SDA stuck low!\n",name); + sdahi(adap); + goto bailout; + } + if ( 0 == getscl(adap) ) { + printk("test_bus: %s SCL unexpected low while SDA high!\n", + adap->name); + goto bailout; + } + scllo(adap); + printk("test_bus:3 scl: %d sda: %d \n",getscl(adap), + getsda(adap)); + if ( 0 != getscl(adap) ) { + + sclhi(adap); + goto bailout; + } + if ( 0 == getsda(adap) ) { + printk("test_bus: %s SDA unexpected low while pulling SCL low!\n", + name); + goto bailout; + } + sclhi(adap); + printk("test_bus:4 scl: %d sda: %d \n",getscl(adap), + getsda(adap)); + if ( 0 == getscl(adap) ) { + printk("test_bus: %s SCL stuck low!\n",name); + sclhi(adap); + goto bailout; + } + if ( 0 == getsda(adap) ) { + printk("test_bus: %s SDA unexpected low while SCL high!\n", + name); + goto bailout; + } + printk("test_bus: %s passed test.\n",name); + return 0; +bailout: + sdahi(adap); + sclhi(adap); + return -ENODEV; + return (0); +} +#endif + +//------------------------------------ +// Utility functions +// + + +// +// Description: This function tries to verify that the device we want to +// talk to on the IIC bus really exists. +// +#if 0 +static inline int try_address(struct i2c_algo_iic_data *adap, + unsigned char addr, int retries) +{ + int i, status, ret = -1; + for (i=0;i<retries;i++) { + i2c_outb(adap, addr); + i2c_start(adap); + status = iic_inb(adap, 1); + if (wait_for_pin(adap, &status) >= 0) { + if ((status & I2C_PCF_LRB) == 0) { + i2c_stop(adap); + break; /* success! */ + } + } + i2c_stop(adap); + udelay(adap->udelay); + } + DEB2(if (i) printk("i2c-algo-iic.o: needed %d retries for %d\n",i, + addr)); + return ret; +} +#endif + + +// +// 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 ret; + + ret = iic_inb(adap, PPC405GP_IICO_BASE+IICO_STS); + if(ret & 0x04) { + //printk(KERN_ERR "Error occurred: "); + ret = iic_inb(adap, PPC405GP_IICO_BASE+IICO_EXTSTS); + if(ret & 0x04) { + //printk(KERN_ERR "Lost arbitration\n"); + } + if(ret & 0x02) { + //printk(KERN_ERR "Incomplete transfer\n"); + } + if(ret & 0x01) { + //printk(KERN_ERR "Master transfer aborted by a NACK during the transfer of the address byte\n"); + } + 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 i2c_algo_iic_data *adap = i2c_adap->algo_data; + int wrcount, status, timeout; + int loops, remainder, i, j; + int ret; + + if( count == 0 ) return 0; + wrcount = 0; + loops = count / 4; + remainder = count % 4; + + if((loops > 1) && (remainder == 0)) { + //printk(KERN_DEBUG "iic_sendbytes: (loops > 1) && (remainder == 0)\n"); + for(i=0; i<(loops-1); i++) { + // + // Write four bytes to master data buffer + // + for(j=0; j<4; j++) { + iic_outb(adap, PPC405GP_IICO_BASE+IICO_MDBUF, + buf[wrcount++]); + } + // + // Issue command to IICO device to begin transmission + // + iic_outb(adap, PPC405GP_IICO_BASE+IICO_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); + if(ret < 0) { + ret = iic_inb(adap, PPC405GP_IICO_BASE+IICO_XFRCNT); + ret = ret & 0x07; + return (wrcount-4+ret); + } + } + } + else if((loops >= 1) && (remainder > 0)){ + //printk(KERN_DEBUG "iic_sendbytes: (loops >= 1)\n"); + for(i=0; i<loops; i++) { + // + // Write four bytes to master data buffer + // + for(j=0; j<4; j++) { + iic_outb(adap, PPC405GP_IICO_BASE+IICO_MDBUF, + buf[wrcount++]); + } + // + // Issue command to IICO device to begin transmission + // + iic_outb(adap, PPC405GP_IICO_BASE+IICO_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); + if(ret < 0) { + ret = iic_inb(adap, PPC405GP_IICO_BASE+IICO_XFRCNT); + ret = ret & 0x07; + return (wrcount-4+ret); + } + } + } + + //printk(KERN_DEBUG "iic_sendbytes: expedite write\n"); + if(remainder == 0) remainder = 4; + // remainder = remainder - 1; + // + // Write the remaining bytes (less than or equal to 4) + // + for(i=0; i<remainder; i++) { + iic_outb(adap, PPC405GP_IICO_BASE+IICO_MDBUF, buf[wrcount++]); + //printk(KERN_DEBUG "iic_sendbytes: data transferred = %x, wrcount = %d\n", buf[wrcount-1], (wrcount-1)); + } + //printk(KERN_DEBUG "iic_sendbytes: Issuing write\n"); + + if(xfer_flag == IIC_COMBINED_XFER) { + iic_outb(adap, PPC405GP_IICO_BASE+IICO_CNTL, (0x09 | ((remainder-1) << 4))); + } + else { + iic_outb(adap, PPC405GP_IICO_BASE+IICO_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); + if(ret < 0) { + ret = iic_inb(adap, PPC405GP_IICO_BASE+IICO_XFRCNT); + ret = ret & 0x07; + return (wrcount-remainder+ret); + } + 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) +{ + int rdcount=0, i, status, timeout; + struct i2c_algo_iic_data *adap = i2c_adap->algo_data; + int loops, remainder, j; + int ret; + + 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, PPC405GP_IICO_BASE+IICO_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); + if(ret < 0) return rdcount; + + 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, PPC405GP_IICO_BASE+IICO_MDBUF); + rdcount++; + //printk(KERN_DEBUG "--->Read one byte\n"); + } + } + } + + else if((loops >= 1) && (remainder > 0)){ + //printk(KERN_DEBUG "iic_readbytes: (loops >=1) && (remainder > 0)\n"); + for(i=0; i<loops; i++) { + // + // Issue command to begin master read (4 bytes maximum) + // + //printk(KERN_DEBUG "--->Issued read command\n"); + iic_outb(adap, PPC405GP_IICO_BASE+IICO_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); + if(ret < 0) return rdcount; + + 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, PPC405GP_IICO_BASE+IICO_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, PPC405GP_IICO_BASE+IICO_CNTL, (0x0b | ((remainder-1) << 4))); + } + else { + iic_outb(adap, PPC405GP_IICO_BASE+IICO_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); + if(ret < 0) return rdcount; + + //printk(KERN_DEBUG "iic_readbyte: Begin reading data buffer\n"); + for(i=0; i<remainder; i++) { + buf[rdcount] = iic_inb(adap, PPC405GP_IICO_BASE+IICO_MDBUF); + // printk(KERN_DEBUG "iic_readbytes: Character read = %x\n", buf[rdcount]); + rdcount++; + } + + return rdcount; +} + + +// +// Description: This function implements combined transactions. Combined +// transactions consist of combinations of reading and writing blocks of data. +// Each transfer (i.e. a read or a write) is separated by a repeated start +// condition. +// +static int iic_combined_transaction(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num) +{ + int i; + struct i2c_msg *pmsg; + int ret; + + DEB2(printk(KERN_DEBUG "Beginning combined transaction\n")); + + for(i=0; i<(num-1); i++) { + pmsg = &msgs[i]; + if(pmsg->flags & I2C_M_RD) { + DEB2(printk(KERN_DEBUG " This one is a read\n")); + ret = iic_readbytes(i2c_adap, pmsg->buf, pmsg->len, IIC_COMBINED_XFER); + } + else if(!(pmsg->flags & I2C_M_RD)) { + DEB2(printk(KERN_DEBUG "This one is a write\n")); + ret = iic_sendbytes(i2c_adap, pmsg->buf, pmsg->len, IIC_COMBINED_XFER); + } + } + // + // Last read or write segment needs to be terminated with a stop + // + pmsg = &msgs[i]; + + if(pmsg->flags & I2C_M_RD) { + DEB2(printk(KERN_DEBUG "Doing the last read\n")); + ret = iic_readbytes(i2c_adap, pmsg->buf, pmsg->len, IIC_SINGLE_XFER); + } + else if(!(pmsg->flags & I2C_M_RD)) { + DEB2(printk(KERN_DEBUG "Doing the last write\n")); + ret = iic_sendbytes(i2c_adap, pmsg->buf, pmsg->len, IIC_SINGLE_XFER); + } + + return ret; +} + + +// +// 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) +{ + unsigned short flags = msg->flags; + unsigned char addr; + +// +// 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, PPC405GP_IICO_BASE + IICO_LMADR, addr); + // + // Write zero to the high slave register since we are + // only using 7 bit addresses + // + iic_outb(adap, PPC405GP_IICO_BASE + IICO_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 i2c_algo_iic_data *adap = i2c_adap->algo_data; + struct i2c_msg *pmsg; + int i = 0; + int ret; + + pmsg = &msgs[i]; + + // + // Clear status register + // + DEB2(printk(KERN_DEBUG "iic_xfer: iic_xfer: Clearing status register\n")); + iic_outb(adap, PPC405GP_IICO_BASE + IICO_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, PPC405GP_IICO_BASE + IICO_STS)) == 0x01) { + ; + } + + // + // Flush master data buf + // + DEB2(printk(KERN_DEBUG "iic_xfer: Clearing master data buffer\n")); + ret = iic_inb(adap, PPC405GP_IICO_BASE + IICO_MDCNTL); + iic_outb(adap, PPC405GP_IICO_BASE + IICO_MDCNTL, ret | 0x40); + + // + // Load slave address + // + DEB2(printk(KERN_DEBUG "iic_xfer: Loading slave address\n")); + ret = iic_doAddress(adap, pmsg, i2c_adap->retries); + + // + // 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 i2c_algo_iic_data *adap = adapter->algo_data; + int ret=0; + int lines; + + lines = iic_inb(adap, PPC405GP_IICO_BASE+IICO_DIRECTCNTL); + + if (cmd == IICO_I2C_SDAHIGH) { + lines = lines & 0x01; + if( lines ) lines = 0x04; + else lines = 0; + iic_outb(adap, PPC405GP_IICO_BASE+IICO_DIRECTCNTL, (0x08|lines)); + } + else if (cmd == IICO_I2C_SDALOW) { + lines = lines & 0x01; + if( lines ) lines = 0x04; + else lines = 0; + iic_outb(adap, PPC405GP_IICO_BASE+IICO_DIRECTCNTL, (0x00|lines)); + } + else if (cmd == IICO_I2C_SCLHIGH) { + lines = lines & 0x02; + if( lines ) lines = 0x08; + else lines = 0; + iic_outb(adap, PPC405GP_IICO_BASE+IICO_DIRECTCNTL, (0x04|lines)); + } + else if (cmd == IICO_I2C_SCLLOW) { + lines = lines & 0x02; + if( lines ) lines = 0x08; + else lines = 0; + iic_outb(adap, PPC405GP_IICO_BASE+IICO_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 = { + "PPC 405GP IIC algorithm", + I2C_ALGO_IIC, + iic_xfer, + NULL, + NULL, /* slave_xmit */ + NULL, /* slave_recv */ + algo_control, /* ioctl */ + iic_func, /* functionality */ +}; + + +/* + * registering functions to load algorithms at runtime + */ + + +// +// Description: Register bus structure +// +int i2c_iic_add_bus(struct i2c_adapter *adap) +{ +// int i, status; + struct i2c_algo_iic_data *iic_adap = adap->algo_data; + +// if (iic_test) { +// int ret = test_bus(iic_adap, adap->name); +// if (ret<0) +// return -ENODEV; +// } + + 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 */ + +#ifdef MODULE + MOD_INC_USE_COUNT; +#endif + + i2c_add_adapter(adap); + iic_init(iic_adap); + + /* scan bus */ + /* By default scanning the bus is turned off. */ + if (iic_scan) { + printk(KERN_INFO " i2c-algo-iic.o: scanning bus %s.\n", + adap->name); +#if 0 + for (i = 0x00; i < 0xff; i+=2) { + // my hack to get rid of this i2c_outb macro + // which doesn't comply with my new definition + // (i.e. it is commented out for now) + // i2c_outb(iic_adap, i); + i2c_start(iic_adap); + if ((wait_for_pin(iic_adap, &status) >= 0) && + ((status & I2C_PCF_LRB) == 0)) { + printk(KERN_INFO "(%02x)",i>>1); + } else { + printk(KERN_INFO "."); + } + i2c_stop(iic_adap); + udelay(iic_adap->udelay); + } + printk(KERN_INFO "\n"); +#endif + } + return 0; +} + + +// +// Done +// +int i2c_iic_del_bus(struct i2c_adapter *adap) +{ + int res; + if ((res = i2c_del_adapter(adap)) < 0) + return res; + DEB2(printk(KERN_DEBUG "i2c-algo-iic.o: adapter unregistered: %s\n",adap->name)); + +#ifdef MODULE + MOD_DEC_USE_COUNT; +#endif + return 0; +} + + +// +// Done +// +int __init i2c_algo_iic_init (void) +{ + printk(KERN_INFO "PPC 405 iic (i2c) algorithm module version %s (%s)\n", I2C_VERSION, I2C_DATE"); + return 0; +} + + +void i2c_algo_iic_exit(void) +{ + return; +} + + +EXPORT_SYMBOL(i2c_iic_add_bus); +EXPORT_SYMBOL(i2c_iic_del_bus); + +// +// The MODULE_* macros resolve to nothing if MODULES is not defined +// when this file is compiled. +// +MODULE_AUTHOR("MontaVista Software <www.mvista.com>"); +MODULE_DESCRIPTION("PPC 405 iic algorithm"); + +MODULE_PARM(iic_test, "i"); +MODULE_PARM(iic_scan, "i"); +MODULE_PARM(i2c_debug,"i"); + +MODULE_PARM_DESC(iic_test, "Test if the I2C bus is available"); +MODULE_PARM_DESC(iic_scan, "Scan for active chips on the bus"); +MODULE_PARM_DESC(i2c_debug, + "debug level - 0 off; 1 normal; 2,3 more verbose; 9 iic-protocol"); + + +// +// This function resolves to init_module (the function invoked when a module +// is loaded via insmod) when this file is compiled with MODULES defined. +// Otherwise (i.e. if you want this driver statically linked to the kernel), +// a pointer to this function is stored in a table and called +// during the intialization of the kernel (in do_basic_setup in /init/main.c) +// +// All this functionality is complements of the macros defined in linux/init.h +module_init(i2c_algo_iic_init); + + +// +// If MODULES is defined when this file is compiled, then this function will +// resolved to cleanup_module. +// +module_exit(i2c_algo_iic_exit); --- /dev/null 1994-07-17 19:46:18.000000000 -0400 +++ linux/include/linux/i2c-algo-ppc405.h 2001-05-30 23:13:25.000000000 -0400 @@ -0,0 +1,55 @@ +/* ------------------------------------------------------------------------- */ +/* i2c-algo-iic.h i2c driver algorithms for IBM PPC 405 IIC adapters */ +/* ------------------------------------------------------------------------- */ +/* Copyright (C) 1995-97 Simon G. Vogl + 1998-99 Hans Berglund + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +/* ------------------------------------------------------------------------- */ + +/* With some changes from Ky?sti M?lkki <kmalkki at cc.hut.fi> and even + Frodo Looijaard <frodol at dds.nl> */ + +/* Modifications by MontaVista Software, August 2000 + Changes made to support the IIC peripheral on the IBM PPC 405 */ + +/* $Id: i2c-algo-ppc405.h,v 1.1 2001/05/31 03:13:25 mds Exp $ */ + +#ifndef I2C_ALGO_IIC_H +#define I2C_ALGO_IIC_H 1 + +/* --- Defines for pcf-adapters --------------------------------------- */ +#include <linux/i2c.h> + +struct i2c_algo_iic_data { + void *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); + + /* local settings */ + int udelay; + int mdelay; + int timeout; +}; + +#define I2C_IIC_ADAP_MAX 16 + +int i2c_iic_add_bus(struct i2c_adapter *); +int i2c_iic_del_bus(struct i2c_adapter *); + +#endif /* I2C_ALGO_IIC_H */ --- linux/drivers/i2c/i2c-elektor.c.orig 2002-05-09 18:21:40.000000000 -0400 +++ linux/drivers/i2c/i2c-elektor.c 2002-05-14 18:01:00.000000000 -0400 @@ -35,11 +35,10 @@ #include <linux/pci.h> #include <asm/irq.h> #include <asm/io.h> - #include <linux/i2c.h> #include <linux/i2c-algo-pcf.h> #include <linux/i2c-elektor.h> -#include "i2c-pcf8584.h" +#include <linux/i2c-pcf8584.h> #define DEFAULT_BASE 0x330 @@ -74,11 +73,12 @@ { int address = ctl ? (base + 1) : base; - if (ctl && irq) { + /* enable irq if any specified for serial operation */ + if (ctl && irq && (val & I2C_PCF_ESO)) { val |= I2C_PCF_ENI; } - DEB3(printk("i2c-elektor.o: Write 0x%X 0x%02X\n", address, val & 255)); + DEB3(printk(KERN_DEBUG "i2c-elektor.o: Write 0x%X 0x%02X\n", address, val & 255)); switch (mmapped) { case 0: /* regular I/O */ @@ -99,7 +99,7 @@ int address = ctl ? (base + 1) : base; int val = mmapped ? readb(address) : inb(address); - DEB3(printk("i2c-elektor.o: Read 0x%X 0x%02X\n", address, val)); + DEB3(printk(KERN_DEBUG "i2c-elektor.o: Read 0x%X 0x%02X\n", address, val)); return (val); } @@ -142,7 +142,7 @@ { if (!mmapped) { if (check_region(base, 2) < 0 ) { - printk("i2c-elektor.o: requested I/O region (0x%X:2) is in use.\n", base); + printk(KERN_ERR "i2c-elektor.o: requested I/O region (0x%X:2) is in use.\n", base); return -ENODEV; } else { request_region(base, 2, "i2c (isa bus adapter)"); @@ -150,7 +150,7 @@ } if (irq > 0) { if (request_irq(irq, pcf_isa_handler, 0, "PCF8584", 0) < 0) { - printk("i2c-elektor.o: Request irq%d failed\n", irq); + printk(KERN_ERR "i2c-elektor.o: Request irq%d failed\n", irq); irq = 0; } else enable_irq(irq); @@ -159,7 +159,7 @@ } -static void __exit pcf_isa_exit(void) +static void pcf_isa_exit(void) { if (irq > 0) { disable_irq(irq); @@ -238,7 +238,7 @@ /* yeap, we've found cypress, let's check config */ if (!pci_read_config_byte(cy693_dev, 0x47, &config)) { - DEB3(printk("i2c-elektor.o: found cy82c693, config register 0x47 = 0x%02x.\n", config)); + DEB3(printk(KERN_DEBUG "i2c-elektor.o: found cy82c693, config register 0x47 = 0x%02x.\n", config)); /* UP2000 board has this register set to 0xe1, but the most significant bit as seems can be @@ -260,7 +260,7 @@ 8.25 MHz (PCI/4) clock (this can be read from cypress) */ clock = I2C_PCF_CLK | I2C_PCF_TRNS90; - printk("i2c-elektor.o: found API UP2000 like board, will probe PCF8584 later.\n"); + printk(KERN_INFO "i2c-elektor.o: found API UP2000 like board, will probe PCF8584 later.\n"); } } } @@ -269,11 +269,11 @@ /* sanity checks for mmapped I/O */ if (mmapped && base < 0xc8000) { - printk("i2c-elektor.o: incorrect base address (0x%0X) specified for mmapped I/O.\n", base); + printk(KERN_ERR "i2c-elektor.o: incorrect base address (0x%0X) specified for mmapped I/O.\n", base); return -ENODEV; } - printk("i2c-elektor.o: i2c pcf8584-isa adapter module\n"); + printk(KERN_INFO "i2c-elektor.o: i2c pcf8584-isa adapter module version %s (%s)\n", I2C_VERSION, I2C_DATE); if (base == 0) { base = DEFAULT_BASE; @@ -283,13 +283,15 @@ init_waitqueue_head(&pcf_wait); #endif if (pcf_isa_init() == 0) { - if (i2c_pcf_add_bus(&pcf_isa_ops) < 0) + if (i2c_pcf_add_bus(&pcf_isa_ops) < 0) { + pcf_isa_exit(); return -ENODEV; + } } else { return -ENODEV; } - printk("i2c-elektor.o: found device at %#x.\n", base); + printk(KERN_ERR "i2c-elektor.o: found device at %#x.\n", base); return 0; } @@ -300,7 +302,9 @@ #ifdef MODULE MODULE_AUTHOR("Hans Berglund <hb at spacetec.no>"); MODULE_DESCRIPTION("I2C-Bus adapter routines for PCF8584 ISA bus adapter"); +#ifdef MODULE_LICENSE MODULE_LICENSE("GPL"); +#endif MODULE_PARM(base, "i"); MODULE_PARM(irq, "i"); --- linux/drivers/i2c/i2c-elv.c.orig 2002-05-09 18:25:30.000000000 -0400 +++ linux/drivers/i2c/i2c-elv.c 2002-05-14 18:01:25.000000000 -0400 @@ -21,7 +21,7 @@ /* With some changes from Ky?sti M?lkki <kmalkki at cc.hut.fi> and even Frodo Looijaard <frodol at dds.nl> */ -/* $Id: i2c-elv.c,v 1.17 2001/07/29 02:44:25 mds Exp $ */ +/* $Id: i2c-elv.c,v 1.21 2001/11/19 18:45:02 mds Exp $ */ #include <linux/kernel.h> #include <linux/module.h> @@ -29,9 +29,7 @@ #include <linux/slab.h> #include <linux/version.h> #include <linux/init.h> - #include <asm/uaccess.h> - #include <linux/ioport.h> #include <asm/io.h> #include <linux/errno.h> @@ -95,14 +93,14 @@ } else { /* test for ELV adap. */ if (inb(base+1) & 0x80) { /* BUSY should be high */ - DEBINIT(printk("i2c-elv.o: Busy was low.\n")); + DEBINIT(printk(KERN_DEBUG "i2c-elv.o: Busy was low.\n")); return -ENODEV; } else { outb(0x0c,base+2); /* SLCT auf low */ udelay(400); if ( !(inb(base+1) && 0x10) ) { outb(0x04,base+2); - DEBINIT(printk("i2c-elv.o: Select was high.\n")); + DEBINIT(printk(KERN_DEBUG "i2c-elv.o: Select was high.\n")); return -ENODEV; } } @@ -115,7 +113,7 @@ return 0; } -static void __exit bit_elv_exit(void) +static void bit_elv_exit(void) { release_region( base , (base == 0x3bc)? 3 : 8 ); } @@ -170,7 +168,7 @@ int __init i2c_bitelv_init(void) { - printk("i2c-elv.o: i2c ELV parallel port adapter module\n"); + printk(KERN_INFO "i2c-elv.o: i2c ELV parallel port adapter module version %s (%s)\n", I2C_VERSION, I2C_DATE); if (base==0) { /* probe some values */ base=DEFAULT_BASE; @@ -190,7 +188,7 @@ return -ENODEV; } } - printk("i2c-elv.o: found device at %#x.\n",base); + printk(KERN_DEBUG "i2c-elv.o: found device at %#x.\n",base); return 0; } @@ -200,7 +198,9 @@ #ifdef MODULE MODULE_AUTHOR("Simon G. Vogl <simon at tk.uni-linz.ac.at>"); MODULE_DESCRIPTION("I2C-Bus adapter routines for ELV parallel port adapter"); +#ifdef MODULE_LICENSE MODULE_LICENSE("GPL"); +#endif MODULE_PARM(base, "i"); --- linux/drivers/i2c/i2c-pcf-epp.c.orig 1969-12-31 19:00:00.000000000 -0500 +++ linux/drivers/i2c/i2c-pcf-epp.c 2002-05-14 18:01:51.000000000 -0400 @@ -0,0 +1,315 @@ +/* ------------------------------------------------------------------------- */ +/* i2c-pcf-epp.c i2c-hw access for PCF8584 style EPP parallel port adapters */ +/* ------------------------------------------------------------------------- */ + +#include <linux/kernel.h> +#include <linux/ioport.h> +#include <linux/module.h> +#include <linux/delay.h> +#include <linux/slab.h> +#include <linux/version.h> +#include <linux/init.h> +#include <linux/parport.h> +#include <asm/irq.h> +#include <asm/io.h> + +#include <linux/i2c.h> +#include <linux/i2c-algo-pcf.h> +#include <linux/i2c-pcf8584.h> + +struct i2c_pcf_epp { + int pe_base; + int pe_irq; + int pe_clock; + int pe_own; +} ; + +#define DEFAULT_BASE 0x378 +#define DEFAULT_IRQ 7 +#define DEFAULT_CLOCK 0x1c +#define DEFAULT_OWN 0x55 + +static int base = 0; +static int irq = 0; +static int clock = 0; +static int own = 0; +static int i2c_debug=0; +static struct i2c_pcf_epp gpe; +#if (LINUX_VERSION_CODE < 0x020301) +static struct wait_queue *pcf_wait = NULL; +#else +static wait_queue_head_t pcf_wait; +#endif +static int pcf_pending; + +/* ----- global defines ----------------------------------------------- */ +#define DEB(x) if (i2c_debug>=1) x +#define DEB2(x) if (i2c_debug>=2) x +#define DEB3(x) if (i2c_debug>=3) x +#define DEBE(x) x /* error messages */ + +/* --- Convenience defines for the EPP/SPP port: */ +#define BASE ((struct i2c_pcf_epp *)(data))->pe_base +#define DATA BASE /* SPP data port */ +#define STAT (BASE+1) /* SPP status port */ +#define CTRL (BASE+2) /* SPP control port */ +#define EADD (BASE+3) /* EPP address port */ +#define EDAT (BASE+4) /* EPP data port */ + +/* ----- local functions ---------------------------------------------- */ + +static void pcf_epp_setbyte(void *data, int ctl, int val) +{ + if (ctl) { + if (gpe.pe_irq > 0) { + DEB3(printk(KERN_DEBUG "i2c-pcf-epp.o: Write control 0x%x\n", + val|I2C_PCF_ENI)); + // set A0 pin HIGH + outb(inb(CTRL) | PARPORT_CONTROL_INIT, CTRL); + // DEB3(printk(KERN_DEBUG "i2c-pcf-epp.o: CTRL port = 0x%x\n", inb(CTRL))); + // DEB3(printk(KERN_DEBUG "i2c-pcf-epp.o: STAT port = 0x%x\n", inb(STAT))); + + // EPP write data cycle + outb(val | I2C_PCF_ENI, EDAT); + } else { + DEB3(printk(KERN_DEBUG "i2c-pcf-epp.o: Write control 0x%x\n", val)); + // set A0 pin HIGH + outb(inb(CTRL) | PARPORT_CONTROL_INIT, CTRL); + outb(val, CTRL); + } + } else { + DEB3(printk(KERN_DEBUG "i2c-pcf-epp.o: Write data 0x%x\n", val)); + // set A0 pin LO + outb(inb(CTRL) & ~PARPORT_CONTROL_INIT, CTRL); + // DEB3(printk(KERN_DEBUG "i2c-pcf-epp.o: CTRL port = 0x%x\n", inb(CTRL))); + // DEB3(printk(KERN_DEBUG "i2c-pcf-epp.o: STAT port = 0x%x\n", inb(STAT))); + outb(val, EDAT); + } +} + +static int pcf_epp_getbyte(void *data, int ctl) +{ + int val; + + if (ctl) { + // set A0 pin HIGH + outb(inb(CTRL) | PARPORT_CONTROL_INIT, CTRL); + val = inb(EDAT); + DEB3(printk(KERN_DEBUG "i2c-pcf-epp.o: Read control 0x%x\n", val)); + } else { + // set A0 pin LOW + outb(inb(CTRL) & ~PARPORT_CONTROL_INIT, CTRL); + val = inb(EDAT); + DEB3(printk(KERN_DEBUG "i2c-pcf-epp.o: Read data 0x%x\n", val)); + } + return (val); +} + +static int pcf_epp_getown(void *data) +{ + return (gpe.pe_own); +} + + +static int pcf_epp_getclock(void *data) +{ + return (gpe.pe_clock); +} + +#if 0 +static void pcf_epp_sleep(unsigned long timeout) +{ + schedule_timeout( timeout * HZ); +} +#endif + +static void pcf_epp_waitforpin(void) { + int timeout = 10; + + if (gpe.pe_irq > 0) { + cli(); + if (pcf_pending == 0) { + interruptible_sleep_on_timeout(&pcf_wait, timeout*HZ); + //udelay(100); + } else { + pcf_pending = 0; + } + sti(); + } else { + udelay(100); + } +} + +static void pcf_epp_handler(int this_irq, void *dev_id, struct pt_regs *regs) { + pcf_pending = 1; + wake_up_interruptible(&pcf_wait); + DEB3(printk(KERN_DEBUG "i2c-pcf-epp.o: in interrupt handler.\n")); +} + + +static int pcf_epp_init(void *data) +{ + if (check_region(gpe.pe_base, 5) < 0 ) { + + printk(KERN_WARNING "Could not request port region with base 0x%x\n", gpe.pe_base); + return -ENODEV; + } else { + request_region(gpe.pe_base, 5, "i2c (EPP parallel port adapter)"); + } + + DEB3(printk(KERN_DEBUG "i2c-pcf-epp.o: init status port = 0x%x\n", inb(0x379))); + + if (gpe.pe_irq > 0) { + if (request_irq(gpe.pe_irq, pcf_epp_handler, 0, "PCF8584", 0) < 0) { + printk(KERN_NOTICE "i2c-pcf-epp.o: Request irq%d failed\n", gpe.pe_irq); + gpe.pe_irq = 0; + } else + disable_irq(gpe.pe_irq); + enable_irq(gpe.pe_irq); + } + // EPP mode initialize + // enable interrupt from nINTR pin + outb(inb(CTRL)|0x14, CTRL); + // clear ERROR bit of STAT + outb(inb(STAT)|0x01, STAT); + outb(inb(STAT)&~0x01,STAT); + + return 0; +} + + +static void pcf_epp_exit(void) +{ + if (gpe.pe_irq > 0) { + disable_irq(gpe.pe_irq); + free_irq(gpe.pe_irq, 0); + } + release_region(gpe.pe_base , 5); +} + + +static int pcf_epp_reg(struct i2c_client *client) +{ + return 0; +} + + +static int pcf_epp_unreg(struct i2c_client *client) +{ + return 0; +} + +static void pcf_epp_inc_use(struct i2c_adapter *adap) +{ +#ifdef MODULE + MOD_INC_USE_COUNT; +#endif +} + +static void pcf_epp_dec_use(struct i2c_adapter *adap) +{ +#ifdef MODULE + MOD_DEC_USE_COUNT; +#endif +} + + +/* ------------------------------------------------------------------------ + * Encapsulate the above functions in the correct operations structure. + * This is only done when more than one hardware adapter is supported. + */ +static struct i2c_algo_pcf_data pcf_epp_data = { + NULL, + pcf_epp_setbyte, + pcf_epp_getbyte, + pcf_epp_getown, + pcf_epp_getclock, + pcf_epp_waitforpin, + 80, 80, 100, /* waits, timeout */ +}; + +static struct i2c_adapter pcf_epp_ops = { + "PCF8584 EPP adapter", + I2C_HW_P_LP, + NULL, + &pcf_epp_data, + pcf_epp_inc_use, + pcf_epp_dec_use, + pcf_epp_reg, + pcf_epp_unreg, +}; + +int __init i2c_pcfepp_init(void) +{ + struct i2c_pcf_epp *pepp = &gpe; + + printk(KERN_DEBUG "i2c-pcf-epp.o: i2c pcf8584-epp adapter module version %s (%s)\n", I2C_VERSION, I2C_DATE); + if (base == 0) + pepp->pe_base = DEFAULT_BASE; + else + pepp->pe_base = base; + + if (irq == 0) + pepp->pe_irq = DEFAULT_IRQ; + else if (irq<0) { + // switch off irq + pepp->pe_irq=0; + } else { + pepp->pe_irq = irq; + } + if (clock == 0) + pepp->pe_clock = DEFAULT_CLOCK; + else + pepp->pe_clock = clock; + + if (own == 0) + pepp->pe_own = DEFAULT_OWN; + else + pepp->pe_own = own; + + pcf_epp_data.data = (void *)pepp; +#if (LINUX_VERSION_CODE >= 0x020301) + init_waitqueue_head(&pcf_wait); +#endif + if (pcf_epp_init(pepp) == 0) { + int ret; + if ( (ret = i2c_pcf_add_bus(&pcf_epp_ops)) < 0) { + printk(KERN_WARNING "i2c_pcf_add_bus caused an error: %d\n",ret); + release_region(pepp->pe_base , 5); + return ret; + } + } else { + + return -ENODEV; + } + printk(KERN_DEBUG "i2c-pcf-epp.o: found device at %#x.\n", pepp->pe_base); + return 0; +} + + +EXPORT_NO_SYMBOLS; + +#ifdef MODULE +MODULE_AUTHOR("Hans Berglund <hb at spacetec.no> \n modified by Ryosuke Tajima <rosk at jsk.t.u-tokyo.ac.jp>"); +MODULE_DESCRIPTION("I2C-Bus adapter routines for PCF8584 EPP parallel port adapter"); + +MODULE_PARM(base, "i"); +MODULE_PARM(irq, "i"); +MODULE_PARM(clock, "i"); +MODULE_PARM(own, "i"); +MODULE_PARM(i2c_debug, "i"); + +int init_module(void) +{ + return i2c_pcfepp_init(); +} + +void cleanup_module(void) +{ + i2c_pcf_del_bus(&pcf_epp_ops); + pcf_epp_exit(); +} + +#endif + + --- /dev/null 1994-07-17 19:46:18.000000000 -0400 +++ linux/include/linux/i2c-pcf8584.h 2001-10-01 20:07:37.000000000 -0400 @@ -0,0 +1,78 @@ +/* -------------------------------------------------------------------- */ +/* i2c-pcf8584.h: PCF 8584 global defines */ +/* -------------------------------------------------------------------- */ +/* Copyright (C) 1996 Simon G. Vogl + 1999 Hans Berglund + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +/* -------------------------------------------------------------------- */ + +/* With some changes from Frodo Looijaard <frodol at dds.nl> */ + +/* $Id: i2c-pcf8584.h,v 1.4 2001/10/02 00:07:37 mds Exp $ */ + +#ifndef I2C_PCF8584_H +#define I2C_PCF8584_H 1 + +/* ----- Control register bits ---------------------------------------- */ +#define I2C_PCF_PIN 0x80 +#define I2C_PCF_ESO 0x40 +#define I2C_PCF_ES1 0x20 +#define I2C_PCF_ES2 0x10 +#define I2C_PCF_ENI 0x08 +#define I2C_PCF_STA 0x04 +#define I2C_PCF_STO 0x02 +#define I2C_PCF_ACK 0x01 + +#define I2C_PCF_START (I2C_PCF_PIN | I2C_PCF_ESO | I2C_PCF_STA | I2C_PCF_ACK) +#define I2C_PCF_STOP (I2C_PCF_PIN | I2C_PCF_ESO | I2C_PCF_STO | I2C_PCF_ACK) +#define I2C_PCF_REPSTART ( I2C_PCF_ESO | I2C_PCF_STA | I2C_PCF_ACK) +#define I2C_PCF_IDLE (I2C_PCF_PIN | I2C_PCF_ESO | I2C_PCF_ACK) + +/* ----- Status register bits ----------------------------------------- */ +/*#define I2C_PCF_PIN 0x80 as above*/ + +#define I2C_PCF_INI 0x40 /* 1 if not initialized */ +#define I2C_PCF_STS 0x20 +#define I2C_PCF_BER 0x10 +#define I2C_PCF_AD0 0x08 +#define I2C_PCF_LRB 0x08 +#define I2C_PCF_AAS 0x04 +#define I2C_PCF_LAB 0x02 +#define I2C_PCF_BB 0x01 + +/* ----- Chip clock frequencies --------------------------------------- */ +#define I2C_PCF_CLK3 0x00 +#define I2C_PCF_CLK443 0x10 +#define I2C_PCF_CLK6 0x14 +#define I2C_PCF_CLK 0x18 +#define I2C_PCF_CLK12 0x1c + +/* ----- transmission frequencies ------------------------------------- */ +#define I2C_PCF_TRNS90 0x00 /* 90 kHz */ +#define I2C_PCF_TRNS45 0x01 /* 45 kHz */ +#define I2C_PCF_TRNS11 0x02 /* 11 kHz */ +#define I2C_PCF_TRNS15 0x03 /* 1.5 kHz */ + + +/* ----- Access to internal registers according to ES1,ES2 ------------ */ +/* they are mapped to the data port ( a0 = 0 ) */ +/* available when ESO == 0 : */ + +#define I2C_PCF_OWNADR 0 +#define I2C_PCF_INTREG I2C_PCF_ES2 +#define I2C_PCF_CLKREG I2C_PCF_ES1 + +#endif /* I2C_PCF8584_H */ --- linux/drivers/i2c/i2c-philips-par.c.orig 2002-05-09 18:21:56.000000000 -0400 +++ linux/drivers/i2c/i2c-philips-par.c 2002-05-14 18:02:15.000000000 -0400 @@ -21,7 +21,7 @@ /* With some changes from Ky?sti M?lkki <kmalkki at cc.hut.fi> and even Frodo Looijaard <frodol at dds.nl> */ -/* $Id: i2c-philips-par.c,v 1.18 2000/07/06 19:21:49 frodo Exp $ */ +/* $Id: i2c-philips-par.c,v 1.23 2002/02/06 08:50:58 simon Exp $ */ #include <linux/kernel.h> #include <linux/ioport.h> @@ -29,7 +29,6 @@ #include <linux/init.h> #include <linux/stddef.h> #include <linux/parport.h> - #include <linux/i2c.h> #include <linux/i2c-algo-bit.h> @@ -190,18 +189,18 @@ struct i2c_par *adapter = kmalloc(sizeof(struct i2c_par), GFP_KERNEL); if (!adapter) { - printk("i2c-philips-par: Unable to malloc.\n"); + printk(KERN_ERR "i2c-philips-par: Unable to malloc.\n"); return; } - printk("i2c-philips-par.o: attaching to %s\n", port->name); + printk(KERN_DEBUG "i2c-philips-par.o: attaching to %s\n", port->name); adapter->pdev = parport_register_device(port, "i2c-philips-par", NULL, NULL, NULL, PARPORT_FLAG_EXCL, NULL); if (!adapter->pdev) { - printk("i2c-philips-par: Unable to register with parport.\n"); + printk(KERN_ERR "i2c-philips-par: Unable to register with parport.\n"); return; } @@ -210,15 +209,18 @@ adapter->bit_lp_data = type ? bit_lp_data2 : bit_lp_data; adapter->bit_lp_data.data = port; + if (parport_claim_or_block(adapter->pdev) < 0 ) { + printk(KERN_ERR "i2c-philips-par: Could not claim parallel port.\n"); + return; + } /* reset hardware to sane state */ - parport_claim_or_block(adapter->pdev); bit_lp_setsda(port, 1); bit_lp_setscl(port, 1); parport_release(adapter->pdev); if (i2c_bit_add_bus(&adapter->adapter) < 0) { - printk("i2c-philips-par: Unable to register with I2C.\n"); + printk(KERN_ERR "i2c-philips-par: Unable to register with I2C.\n"); parport_unregister_device(adapter->pdev); kfree(adapter); return; /* No good */ @@ -264,7 +266,7 @@ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,4) struct parport *port; #endif - printk("i2c-philips-par.o: i2c Philips parallel port adapter module\n"); + printk(KERN_INFO "i2c-philips-par.o: i2c Philips parallel port adapter module version %s (%s)\n", I2C_VERSION, I2C_DATE); #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,4) parport_register_driver(&i2c_driver); @@ -291,7 +293,9 @@ MODULE_AUTHOR("Simon G. Vogl <simon at tk.uni-linz.ac.at>"); MODULE_DESCRIPTION("I2C-Bus adapter routines for Philips parallel port adapter"); +#ifdef MODULE_LICENSE MODULE_LICENSE("GPL"); +#endif MODULE_PARM(type, "i"); --- linux/drivers/i2c/i2c-ppc405.c.orig 1969-12-31 19:00:00.000000000 -0500 +++ linux/drivers/i2c/i2c-ppc405.c 2002-05-14 18:02:35.000000000 -0400 @@ -0,0 +1,399 @@ +/* + ------------------------------------------------------------------------- + i2c-adap-ppc405.c i2c-hw access for the IIC peripheral on the IBM PPC 405 + ------------------------------------------------------------------------- + + Ian DaSilva, MontaVista Software, Inc. + idasilva at mvista.com or source at mvista.com + + Copyright 2000 MontaVista Software Inc. + + Changes made to support the IIC peripheral on the IBM PPC 405 + + + ---------------------------------------------------------------------------- + This file was highly leveraged from i2c-elektor.c, which was created + by Simon G. Vogl and Hans Berglund: + + + Copyright (C) 1995-97 Simon G. Vogl + 1998-99 Hans Berglund + + With some changes from Ky?sti M?lkki <kmalkki at cc.hut.fi> and even + Frodo Looijaard <frodol at dds.nl> + + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + ---------------------------------------------------------------------------- +*/ + + +#include <linux/kernel.h> +#include <linux/ioport.h> +#include <linux/module.h> +#include <linux/delay.h> +#include <linux/slab.h> +#include <linux/version.h> +#include <linux/init.h> +#include <asm/irq.h> +#include <asm/io.h> +#include <linux/i2c.h> +#include <linux/i2c-algo-ppc405.h> +#include <linux/i2c-ppc405adap.h> +#include <linux/i2c-ppc405.h> + +#ifdef MODULE_LICENSE +MODULE_LICENSE("GPL"); +#endif + +#define DEFAULT_BASE 0xEF600500 +#define DEFAULT_IRQ 2 +#define DEFAULT_CLOCK 50 +#define DEFAULT_OWN 0x55 + +static int base = 0; +static int irq = 0; +static int clock = 0; +static int own = 0; +static int i2c_debug=0; +static struct iic_ppc405 gpi; +#if (LINUX_VERSION_CODE < 0x020301) +static struct wait_queue *iic_wait = NULL; +#else +static wait_queue_head_t iic_wait; +#endif +static int iic_pending; + +/* ----- global defines ----------------------------------------------- */ +#define DEB(x) if (i2c_debug>=1) x +#define DEB2(x) if (i2c_debug>=2) x +#define DEB3(x) if (i2c_debug>=3) x +#define DEBE(x) x /* error messages */ + + +/* --- Convenience defines for the i2c port: */ +#define BASE ((struct iic_ppc405 *)(data))->iic_base + +/* ----- local functions ---------------------------------------------- */ + +// +// Description: Write a byte to IIC hardware +// +static void iic_ppc405_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_ppc405_getbyte(void *data, int ctl) +{ + int val; + + DEB3(printk("i2c-ppc405_getbyte: Read IIC register\n")); + val = readb(ctl); + DEB3(printk("i2c-ppc405getbyte: Read Data 0x%02X\n", val)); + 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_ppc405_getown(void *data) +{ + return (gpi.iic_own); +} + + +// +// Description: Return the clock rate +// +static int iic_ppc405_getclock(void *data) +{ + return (gpi.iic_clock); +} + + +#if 0 +static void iic_ppc405_sleep(unsigned long timeout) +{ + schedule_timeout( timeout * HZ); +} +#endif + + +// +// Description: Put this process to sleep. We will wake up when the +// IIC controller interrupts. +// +static void iic_ppc405_waitforpin(void) { + + int timeout = 2; + + //printk("iic_ppc405_waitforpin: At top of function\n"); + // + // 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 (gpi.iic_irq > 0) { + cli(); + if (iic_pending == 0) { + //printk("iic_ppc405_waitforpin: calling interruptible_sleep_on_timeout\n"); + interruptible_sleep_on_timeout(&iic_wait, timeout*HZ ); + } else + iic_pending = 0; + sti(); + } 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_ppc405_waitforpin: exitting\n"); +} + + +// +// Description: The registered interrupt handler +// +static void iic_ppc405_handler(int this_irq, void *dev_id, struct pt_regs *regs) +{ + int ret; + + iic_pending = 1; + DEB2(printk("iic_ppc405_handler: in interrupt handler\n")); + // Read status register + ret = readb(0xef600508); + DEB2(printk("iic_ppc405_handler: status = %x\n", ret)); + // Clear status register. See IBM PPC 405 reference manual for details + writeb(0x0a, 0xef600508); + wake_up_interruptible(&iic_wait); +} + + +// +// 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(void) +{ +// this is not a pci io region, don't use request_region() +// if (check_region(gpi.iic_base, 17) < 0 ) { +// return -ENODEV; +// } else { +// request_region(gpi.iic_base, 17, "i2c (i2c bus adapter)"); +// } + if (gpi.iic_irq > 0) { + if (request_irq(gpi.iic_irq, iic_ppc405_handler, 0, "PPC405 IIC", 0) < 0) { + printk(KERN_ERR "iic_hw_resrc_init: Request irq%d failed\n", gpi.iic_irq); + gpi.iic_irq = 0; + } else + DEB3(printk("iic_hw_resrc_init: Enabled interrupt\n")); + enable_irq(gpi.iic_irq); + } + return 0; +} + + +// +// Description: Release irq and memory +// +static void iic_ppc405_release(void) +{ + if (gpi.iic_irq > 0) { + disable_irq(gpi.iic_irq); + free_irq(gpi.iic_irq, 0); + } + release_region(gpi.iic_base , 2); +} + + +// +// Description: Does nothing +// +static int iic_ppc405_reg(struct i2c_client *client) +{ + return 0; +} + + +// +// Description: Does nothing +// +static int iic_ppc405_unreg(struct i2c_client *client) +{ + return 0; +} + + +// +// Description: If this compiled as a module, then increment the count +// +static void iic_ppc405_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_ppc405_dec_use(struct i2c_adapter *adap) +{ +#ifdef MODULE + MOD_DEC_USE_COUNT; +#endif +} + + +/* ------------------------------------------------------------------------ + * Encapsulate the above functions in the correct operations structure. + * This is only done when more than one hardware adapter is supported. + */ +static struct i2c_algo_iic_data iic_ppc405_data = { + NULL, + iic_ppc405_setbyte, + iic_ppc405_getbyte, + iic_ppc405_getown, + iic_ppc405_getclock, + iic_ppc405_waitforpin, + 80, 80, 100, /* waits, timeout */ +}; + +static struct i2c_adapter iic_ppc405_ops = { + "PPC405 IIC adapter", + I2C_HW_I_IIC, + NULL, + &iic_ppc405_data, + iic_ppc405_inc_use, + iic_ppc405_dec_use, + iic_ppc405_reg, + iic_ppc405_unreg, +}; + + +// +// 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_ppc405_init(void) +{ + + struct iic_ppc405 *piic = &gpi; + + +// printk(KERN_INFO "Infinite loop\n"); +// // Soft reset +// writeb(0x1, 0xef60050f); +// while(1) { +// // Set SDA line low +// writeb(0x8, 0xef600510); +// } + + printk(KERN_INFO "iic_ppc405_init: PPC 405 iic adapter module version %s (%s)\n", I2C_VERSION, I2C_DATE); + if (base == 0) + piic->iic_base = DEFAULT_BASE; + else + piic->iic_base = base; + + if (irq == 0) + piic->iic_irq = DEFAULT_IRQ; + else + piic->iic_irq = irq; + + if (clock == 0) + piic->iic_clock = DEFAULT_CLOCK; + else + piic->iic_clock = clock; + + if (own == 0) + piic->iic_own = DEFAULT_OWN; + else + piic->iic_own = own; + + iic_ppc405_data.data = (void *)piic; +#if (LINUX_VERSION_CODE >= 0x020301) + init_waitqueue_head(&iic_wait); +#endif + if (iic_hw_resrc_init() == 0) { + if (i2c_iic_add_bus(&iic_ppc405_ops) < 0) + return -ENODEV; + } else { + return -ENODEV; + } + printk(KERN_INFO "iic_ppc405_init: found device at %#x.\n", piic->iic_base); + return 0; +} + + +static void iic_ppc405_exit(void) +{ + i2c_iic_del_bus(&iic_ppc405_ops); + iic_ppc405_release(); +} + +EXPORT_NO_SYMBOLS; + +// +// If modules is NOT defined when this file is compiled, then the MODULE_* +// macros will resolve to nothing +// +MODULE_AUTHOR("MontaVista Software <www.mvista.com>"); +MODULE_DESCRIPTION("I2C-Bus adapter routines for PPC 405 IIC bus adapter"); + +MODULE_PARM(base, "i"); +MODULE_PARM(irq, "i"); +MODULE_PARM(clock, "i"); +MODULE_PARM(own, "i"); +MODULE_PARM(i2c_debug,"i"); + + +// +// Description: Called when module is loaded or when kernel is intialized. +// If MODULES is defined when this file is compiled, then this function will +// resolve to init_module (the function called when insmod is invoked for a +// module). Otherwise, this function is called early in the boot, when the +// kernel is intialized. Check out /include/init.h to see how this works. +// +module_init(iic_ppc405_init); + + + +// +// Description: Resolves to module_cleanup when MODULES is defined. +// +module_exit(iic_ppc405_exit); --- /dev/null 1994-07-17 19:46:18.000000000 -0400 +++ linux/include/linux/i2c-ppc405.h 2001-05-30 23:13:25.000000000 -0400 @@ -0,0 +1,125 @@ +/* + -------------------------------------------------------------------- + i2c-ppc405.h: Global defines for the I2C controller on board the + IBM 405 PPC processor. + -------------------------------------------------------------------- + + Ian DaSilva, MontaVista Software, Inc. + idasilva at mvista.com or source at mvista.com + + Copyright 2000 MontaVista Software Inc. + + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + + */ + + +#ifndef I2C_PPC405_H +#define I2C_PPC405_H 1 + +/* Base Address */ +#define PPC405GP_IICO_BASE 0xef600500 + +/* Registers */ +#define IICO_MDBUF 0x0 +#define IICO_SDBUF 0x2 +#define IICO_LMADR 0x4 +#define IICO_HMADR 0x5 +#define IICO_CNTL 0x6 +#define IICO_MDCNTL 0x7 +#define IICO_STS 0x8 +#define IICO_EXTSTS 0x9 +#define IICO_LSADR 0xa +#define IICO_HSADR 0xb +#define IICO_CLKDIV 0xc +#define IICO_INTRMSK 0xd +#define IICO_XFRCNT 0xe +#define IICO_XTCNTLSS 0xf +#define IICO_DIRECTCNTL 0x10 + + +#if 0 +/* + * IICO Control Register + */ + +/* HMT */ +#define IICO_NORMAL_TRANSFER 0x00 +#define IICO_ISSUE_STOP 0x80 + +/* AMD */ +#define IICO_SEVEN_BIT_ADDR 0x00 +#define IICO_TEN_BIT_ADDR 0x40 + +/* TCT */ +#define IICO_TRANSFER_1_BYTE 0x00 +#define IICO_TRANSFER_2_BYTES 0x10 +#define IICO_TRANSFER_3_BYTES 0x20 +#define IICO_TRANSFER_4_BYTES 0x30 + +/* RPST */ +#define IICO_NORMAL_START 0x00 +#define IICO_REPEATED_START 0x08 + +/* CHT */ +#define IICO_SINGLE_TRANSFER 0x00 +#define IICO_SEQUENCE_TRANSFER 0x40 + +/* RW */ +#define IICO_WRITE 0x00 +#define IICO_READ 0x20 + +/* PT */ +#define IICO_START_TRANSFER 0x01 + + + +/* + * IICO Mode Control Register + */ + +/* FSDB */ +#define IICO_FLUSH_SLAVE_DATA_BUFFER 0x80 + +/* FMDB */ +#define IICO_FLUSH_MASTER_DATA_BUFFER 0x40 + +/* EGC */ +#define IICO_ENABLE_GENERAL_CALL 0x20 + +/* FSM */ +#define IICO_STANDARD_MODE 0x00 /* Transfers at 100 kHz */ +#define IICO_FAST_MODE 0x10 /* Transfers at 400 kHz */ + +/* ESM */ +#define IICO_ENABLE_SLAVE_MODE 0x08 + +/* EINT */ +#define IICO_ENABLE_INTERRUPTS 0x04 + +/* EUBS */ +#define IICO_EXIT_UNKNOWN_BUS_STATE 0x02 + +/* HSCL */ + +#endif + +#endif /* I2C_PPC405_H */ --- /dev/null 1994-07-17 19:46:18.000000000 -0400 +++ linux/include/linux/i2c-ppc405adap.h 2001-05-30 23:13:25.000000000 -0400 @@ -0,0 +1,46 @@ +/* ------------------------------------------------------------------------- */ +/* i2c-ppc405adap.h i2c-hw access for IBM PPC 405 IIC bus adapters */ +/* ------------------------------------------------------------------------- */ +/* Copyright (C) 1995-97 Simon G. Vogl + 1998-99 Hans Berglund + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +/* ------------------------------------------------------------------------- */ + +/* With some changes from Ky?sti M?lkki <kmalkki at cc.hut.fi> and even + Frodo Looijaard <frodol at dds.nl> */ + +/* Modified by MontaVista Software, August 2000 + Added support for the IIC peripheral on the IBM PPC 405 */ + +/* $Id: i2c-ppc405adap.h,v 1.1 2001/05/31 03:13:25 mds Exp $ */ + +#ifndef I2C_PPC405ADAP_H +#define I2C_PPC405ADAP_H 1 + +/* + * This struct contains the hw-dependent functions of IBM PPC 405 IIC adapters + * to manipulate the registers, and to init any hw-specific features. + */ + +struct iic_ppc405 { + int iic_base; + int iic_irq; + int iic_clock; + int iic_own; +}; + + +#endif /* I2C_IBM405ADAP_H */ --- linux/drivers/i2c/i2c-pport.c.orig 1969-12-31 19:00:00.000000000 -0500 +++ linux/drivers/i2c/i2c-pport.c 2002-05-14 18:03:19.000000000 -0400 @@ -0,0 +1,254 @@ +/* ------------------------------------------------------------------------- */ +/* i2c-pport.c i2c-hw access for primitive i2c par. port adapter */ +/* ------------------------------------------------------------------------- */ +/* Copyright (C) 2001 Daniel Smolik + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +/* ------------------------------------------------------------------------- */ + +/* + See doc/i2c-pport for instructions on wiring to the + parallel port connector. + + Cut & paste :-) based on Velleman K9000 driver by Simon G. Vogl +*/ + + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/delay.h> +#include <linux/slab.h> +#include <linux/version.h> +#include <linux/init.h> +#include <asm/uaccess.h> +#include <linux/ioport.h> +#include <asm/io.h> +#include <linux/errno.h> +#include <linux/i2c.h> +#include <linux/i2c-algo-bit.h> + +#ifdef MODULE_LICENSE +MODULE_LICENSE("GPL"); +#endif + +#define DEFAULT_BASE 0x378 +static int base=0; +static unsigned char PortData = 0; + +/* ----- global defines ----------------------------------------------- */ +#define DEB(x) /* should be reasonable open, close &c. */ +#define DEB2(x) /* low level debugging - very slow */ +#define DEBE(x) x /* error messages */ +#define DEBINIT(x) x /* detection status messages */ + +/* --- Convenience defines for the parallel port: */ +#define BASE (unsigned int)(data) +#define DATA BASE /* Centronics data port */ +#define STAT (BASE+1) /* Centronics status port */ +#define CTRL (BASE+2) /* Centronics control port */ + +/* we will use SDA - Auto Linefeed(14) bit 1 POUT */ +/* we will use SCL - Initialize printer(16) BUSY bit 2*/ + +#define SET_SCL | 0x04 +#define CLR_SCL & 0xFB + + + + +#define SET_SDA & 0x04 +#define CLR_SDA | 0x02 + + +/* ----- local functions ---------------------------------------------- */ + + +static void bit_pport_setscl(void *data, int state) +{ + if (state) { + //high + PortData = PortData SET_SCL; + } else { + //low + PortData = PortData CLR_SCL; + } + outb(PortData, CTRL); +} + +static void bit_pport_setsda(void *data, int state) +{ + if (state) { + + PortData = PortData SET_SDA; + } else { + + PortData = PortData CLR_SDA; + } + outb(PortData, CTRL); +} + +static int bit_pport_getscl(void *data) +{ + + return ( 4 == ( (inb_p(CTRL)) & 0x04 ) ); +} + +static int bit_pport_getsda(void *data) +{ + return ( 0 == ( (inb_p(CTRL)) & 0x02 ) ); +} + +static int bit_pport_init(void) +{ + //release_region( (base+2) ,1); + + if (check_region((base+2),1) < 0 ) { + return -ENODEV; + } else { + + /* test for PPORT adap. */ + + + PortData=inb(base+2); + PortData= (PortData SET_SDA) SET_SCL; + outb(PortData,base+2); + + if (!(inb(base+2) | 0x06)) { /* SDA and SCL will be high */ + DEBINIT(printk("i2c-pport.o: SDA and SCL was low.\n")); + return -ENODEV; + } else { + + /*SCL high and SDA low*/ + PortData = PortData SET_SCL CLR_SDA; + outb(PortData,base+2); + udelay(400); + if ( !(inb(base+2) | 0x4) ) { + //outb(0x04,base+2); + DEBINIT(printk("i2c-port.o: SDA was high.\n")); + return -ENODEV; + } + } + request_region((base+2),1, + "i2c (PPORT adapter)"); + bit_pport_setsda((void*)base,1); + bit_pport_setscl((void*)base,1); + } + return 0; +} + +static void bit_pport_exit(void) +{ + release_region((base+2),1); +} + +static int bit_pport_reg(struct i2c_client *client) +{ + return 0; +} + +static int bit_pport_unreg(struct i2c_client *client) +{ + release_region((base+2),1); + return 0; +} + +static void bit_pport_inc_use(struct i2c_adapter *adap) +{ +#ifdef MODULE + MOD_INC_USE_COUNT; +#endif +} + +static void bit_pport_dec_use(struct i2c_adapter *adap) +{ +#ifdef MODULE + MOD_DEC_USE_COUNT; +#endif +} + +/* ------------------------------------------------------------------------ + * Encapsulate the above functions in the correct operations structure. + * This is only done when more than one hardware adapter is supported. + */ +static struct i2c_algo_bit_data bit_pport_data = { + NULL, + bit_pport_setsda, + bit_pport_setscl, + bit_pport_getsda, + bit_pport_getscl, + //NULL, + 40, 80, 100, /* waits, timeout */ +}; + +static struct i2c_adapter bit_pport_ops = { + "Primitive Parallel port adaptor", + I2C_HW_B_PPORT, + NULL, + &bit_pport_data, + bit_pport_inc_use, + bit_pport_dec_use, + bit_pport_reg, + bit_pport_unreg, +}; + +static int __init i2c_bitpport_init(void) +{ + printk("i2c-pport.o: i2c Primitive parallel port adapter module version %s (%s)\n", I2C_VERSION, I2C_DATE); + + if (base==0) { + /* probe some values */ + base=DEFAULT_BASE; + bit_pport_data.data=(void*)DEFAULT_BASE; + if (bit_pport_init()==0) { + if(i2c_bit_add_bus(&bit_pport_ops) < 0) + return -ENODEV; + } else { + return -ENODEV; + } + } else { + bit_pport_data.data=(void*)base; + if (bit_pport_init()==0) { + if(i2c_bit_add_bus(&bit_pport_ops) < 0) + return -ENODEV; + } else { + return -ENODEV; + } + } + printk("i2c-pport.o: found device at %#x.\n",base); + return 0; +} + + +EXPORT_NO_SYMBOLS; + +#ifdef MODULE +MODULE_AUTHOR("Daniel Smolik <marvin at sitour.cz>"); +MODULE_DESCRIPTION("I2C-Bus adapter routines for Primitive parallel port adapter") +; + +MODULE_PARM(base, "i"); + +int init_module(void) +{ + return i2c_bitpport_init(); +} + +void cleanup_module(void) +{ + i2c_bit_del_bus(&bit_pport_ops); + bit_pport_exit(); +} + +#endif --- linux/drivers/i2c/i2c-rpx.c.orig 1969-12-31 19:00:00.000000000 -0500 +++ linux/drivers/i2c/i2c-rpx.c 2001-09-08 12:27:03.000000000 -0400 @@ -0,0 +1,133 @@ +/* + * Embedded Planet RPX Lite MPC8xx CPM I2C interface. + * Copyright (c) 1999 Dan Malek (dmalek at jlc.net). + * + * moved into proper i2c interface; + * Brad Parker (brad at heeltoe.com) + * + * RPX lite specific parts of the i2c interface + */ + +#include <linux/kernel.h> +#include <linux/ioport.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/stddef.h> +#include <linux/parport.h> + +#include <asm/mpc8xx.h> +#include "../../arch/ppc/8xx_io/commproc.h" + +#include <linux/i2c.h> +#include <linux/i2c-algo-8xx.h> + +static void +rpx_iic_init(struct i2c_algo_8xx_data *data) +{ + volatile cpm8xx_t *cp; + volatile immap_t *immap; + + cp = cpmp; /* Get pointer to Communication Processor */ + immap = (immap_t *)IMAP_ADDR; /* and to internal registers */ + + data->iip = (iic_t *)&cp->cp_dparam[PROFF_IIC]; + + /* Check for and use a microcode relocation patch. + */ + if ((data->reloc = data->iip->iic_rpbase)) + data->iip = (iic_t *)&cp->cp_dpmem[data->iip->iic_rpbase]; + + data->i2c = (i2c8xx_t *)&(immap->im_i2c); + data->cp = cp; + + /* Initialize Port B IIC pins. + */ + cp->cp_pbpar |= 0x00000030; + cp->cp_pbdir |= 0x00000030; + cp->cp_pbodr |= 0x00000030; + + /* Allocate space for two transmit and two receive buffer + * descriptors in the DP ram. + */ + data->dp_addr = m8xx_cpm_dpalloc(sizeof(cbd_t) * 4); + + /* ptr to i2c area */ + data->i2c = (i2c8xx_t *)&(((immap_t *)IMAP_ADDR)->im_i2c); +} + +static int rpx_install_isr(int irq, void (*func)(void *), void *data) +{ + /* install interrupt handler */ + cpm_install_handler(irq, func, data); + + return 0; +} + +static int rpx_reg(struct i2c_client *client) +{ + return 0; +} + +static int rpx_unreg(struct i2c_client *client) +{ + return 0; +} + +static void rpx_inc_use(struct i2c_adapter *adap) +{ +#ifdef MODULE + MOD_INC_USE_COUNT; +#endif +} + +static void rpx_dec_use(struct i2c_adapter *adap) +{ +#ifdef MODULE + MOD_DEC_USE_COUNT; +#endif +} + +static struct i2c_algo_8xx_data rpx_data = { + setisr: rpx_install_isr +}; + + +static struct i2c_adapter rpx_ops = { + "rpx", + I2C_HW_MPC8XX_EPON, + NULL, + &rpx_data, + rpx_inc_use, + rpx_dec_use, + rpx_reg, + rpx_unreg, +}; + +int __init i2c_rpx_init(void) +{ + printk("i2c-rpx.o: i2c RPX Lite module version %s (%s)\n", I2C_VERSION, I2C_DATE); + + /* reset hardware to sane state */ + rpx_iic_init(&rpx_data); + + if (i2c_8xx_add_bus(&rpx_ops) < 0) { + printk("i2c-rpx: Unable to register with I2C\n"); + return -ENODEV; + } + + return 0; +} + +void __exit i2c_rpx_exit(void) +{ + i2c_8xx_del_bus(&rpx_ops); +} + +#ifdef MODULE +MODULE_AUTHOR("Dan Malek <dmalek at jlc.net>"); +MODULE_DESCRIPTION("I2C-Bus adapter routines for EP RPX Lite"); + +module_init(i2c_rpx_init); +module_exit(i2c_rpx_exit); +#endif + --- linux/drivers/i2c/i2c-velleman.c.orig 2002-05-09 18:23:06.000000000 -0400 +++ linux/drivers/i2c/i2c-velleman.c 2002-05-14 18:04:11.000000000 -0400 @@ -18,7 +18,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* ------------------------------------------------------------------------- */ -/* $Id: i2c-velleman.c,v 1.19 2000/01/24 02:06:33 mds Exp $ */ +/* $Id: i2c-velleman.c,v 1.23 2001/11/19 18:45:02 mds Exp $ */ #include <linux/kernel.h> #include <linux/ioport.h> @@ -27,7 +27,6 @@ #include <linux/string.h> /* for 2.0 kernels to get NULL */ #include <asm/errno.h> /* for 2.0 kernels to get ENODEV */ #include <asm/io.h> - #include <linux/i2c.h> #include <linux/i2c-algo-bit.h> @@ -91,7 +90,7 @@ static int bit_velle_init(void) { if (check_region(base,(base == 0x3bc)? 3 : 8) < 0 ) { - DEBE(printk("i2c-velleman.o: Port %#x already in use.\n", + DEBE(printk(KERN_DEBUG "i2c-velleman.o: Port %#x already in use.\n", base)); return -ENODEV; } else { @@ -103,7 +102,7 @@ return 0; } -static void __exit bit_velle_exit(void) +static void bit_velle_exit(void) { release_region( base , (base == 0x3bc)? 3 : 8 ); } @@ -160,7 +159,7 @@ int __init i2c_bitvelle_init(void) { - printk("i2c-velleman.o: i2c Velleman K8000 adapter module\n"); + printk(KERN_INFO "i2c-velleman.o: i2c Velleman K8000 adapter module version %s (%s)\n", I2C_VERSION, I2C_DATE); if (base==0) { /* probe some values */ base=DEFAULT_BASE; @@ -180,7 +179,7 @@ return -ENODEV; } } - printk("i2c-velleman.o: found device at %#x.\n",base); + printk(KERN_DEBUG "i2c-velleman.o: found device at %#x.\n",base); return 0; } @@ -189,7 +188,9 @@ #ifdef MODULE MODULE_AUTHOR("Simon G. Vogl <simon at tk.uni-linz.ac.at>"); MODULE_DESCRIPTION("I2C-Bus adapter routines for Velleman K8000 adapter"); +#ifdef MODULE_LICENSE MODULE_LICENSE("GPL"); +#endif MODULE_PARM(base, "i"); -- Albert Cranford Deerfield Beach FL USA ac9410 at bellsouth.net