On Sun, Sep 14, 2003 at 12:06:24AM +0200, Jean Delvare wrote: > > > This updates the current 2.6 PPC 4xx driver to the rewritten version > > we have in the PPC development tree. It is cleaner, has less bugs, > > and has more features. Please apply. > > Hm, we also have a copy of that driver in our I2C CVS repository > (intended to be used with 2.4 kernels). If you want us to update is as > well, please provide a patch against current CVS. Oddly enough, I thought I sent the 2.4 version in a separate mail. Nothing in my sent-mail folder though, at least I had it in my pending patch area. :) Here it is. Thanks, Matt diff -N -u2 -r i2c-orig/kernel/i2c-adap-ibm_ocp.c i2c/kernel/i2c-adap-ibm_ocp.c --- i2c-orig/kernel/i2c-adap-ibm_ocp.c 2003-01-21 01:08:16.000000000 -0700 +++ i2c/kernel/i2c-adap-ibm_ocp.c 1969-12-31 17:00:00.000000000 -0700 @@ -1,346 +0,0 @@ -/* - ------------------------------------------------------------------------- - i2c-adap-ibm_ocp.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. - ---------------------------------------------------------------------------- - - History: 01/20/12 - Armin - akuster at mvista.com - ported up to 2.4.16+ - - Version 02/03/25 - Armin - converted to ocp format - removed commented out or #if 0 code - - TODO: convert to ocp_register - add PM hooks - -*/ - - -#include <linux/kernel.h> -#include <linux/ioport.h> -#include <linux/module.h> -#include <linux/delay.h> -#include <linux/slab.h> -#include <linux/init.h> -#include "i2c.h" -#include "i2c-algo-ibm_ocp.h" -#include <asm/irq.h> -#include <asm/io.h> -#include <asm/ocp.h> - -/* - * This next section is configurable, and it is used to set the number - * of i2c controllers in the system. The default number of instances is 1, - * however, this should be changed to reflect your system's configuration. - */ - -/* - * The STB03xxx, with a PPC405 core, has two i2c controllers. - */ -//(sizeof(IIC_ADDR)/sizeof(struct iic_regs)) -extern iic_t *IIC_ADDR[]; -static struct iic_ibm iic_ibmocp_adaps[IIC_NUMS][5]; - -static struct i2c_algo_iic_data *iic_ibmocp_data[IIC_NUMS]; -static struct i2c_adapter *iic_ibmocp_ops[IIC_NUMS]; - -static int i2c_debug=0; -static wait_queue_head_t iic_wait[IIC_NUMS]; -static int iic_pending; -static spinlock_t irq_driver_lock = SPIN_LOCK_UNLOCKED; - - -/* ----- global defines ----------------------------------------------- */ -#define DEB(x) if (i2c_debug>=1) x -#define DEB2(x) if (i2c_debug>=2) x -#define DEB3(x) if (i2c_debug>=3) x -#define DEBE(x) x /* error messages */ - -/* ----- local functions ---------------------------------------------- */ - -// -// Description: Write a byte to IIC hardware -// -static void iic_ibmocp_setbyte(void *data, int ctl, int val) -{ - // writeb resolves to a write to the specified memory location - // plus a call to eieio. eieio ensures that all instructions - // preceding it are completed before any further stores are - // completed. - // Delays at this level (to protect writes) are not needed here. - writeb(val, ctl); -} - - -// -// Description: Read a byte from IIC hardware -// -static int iic_ibmocp_getbyte(void *data, int ctl) -{ - int val; - - val = readb(ctl); - return (val); -} - - -// -// Description: Return our slave address. This is the address -// put on the I2C bus when another master on the bus wants to address us -// as a slave -// -static int iic_ibmocp_getown(void *data) -{ - return(((struct iic_ibm *)(data))->iic_own); -} - - -// -// Description: Return the clock rate -// -static int iic_ibmocp_getclock(void *data) -{ - return(((struct iic_ibm *)(data))->iic_clock); -} - - - -// -// Description: Put this process to sleep. We will wake up when the -// IIC controller interrupts. -// -static void iic_ibmocp_waitforpin(void *data) { - - int timeout = 2; - struct iic_ibm *priv_data = data; - - // - // If interrupts are enabled (which they are), then put the process to - // sleep. This process will be awakened by two events -- either the - // the IIC peripheral interrupts or the timeout expires. - // - if (priv_data->iic_irq > 0) { - spin_lock_irq(&irq_driver_lock); - if (iic_pending == 0) { - interruptible_sleep_on_timeout(&(iic_wait[priv_data->index]), timeout*HZ ); - } else - iic_pending = 0; - spin_unlock_irq(&irq_driver_lock); - } else { - // - // If interrupts are not enabled then delay for a reasonable amount - // of time and return. We expect that by time we return to the calling - // function that the IIC has finished our requested transaction and - // the status bit reflects this. - // - // udelay is probably not the best choice for this since it is - // the equivalent of a busy wait - // - udelay(100); - } - //printk("iic_ibmocp_waitforpin: exitting\n"); -} - - -// -// Description: The registered interrupt handler -// -static void iic_ibmocp_handler(int this_irq, void *dev_id, struct pt_regs *regs) -{ - int ret; - struct iic_regs *iic; - struct iic_ibm *priv_data = dev_id; - iic = (struct iic_regs *) priv_data->iic_base; - iic_pending = 1; - DEB2(printk("iic_ibmocp_handler: in interrupt handler\n")); - // Read status register - ret = readb((int) &(iic->sts)); - DEB2(printk("iic_ibmocp_handler: status = %x\n", ret)); - // Clear status register. See IBM PPC 405 reference manual for details - writeb(0x0a, (int) &(iic->sts)); - wake_up_interruptible(&(iic_wait[priv_data->index])); -} - - -// -// Description: This function is very hardware dependent. First, we lock -// the region of memory where out registers exist. Next, we request our -// interrupt line and register its associated handler. Our IIC peripheral -// uses interrupt number 2, as specified by the 405 reference manual. -// -static int iic_hw_resrc_init(int instance) -{ - - DEB(printk("iic_hw_resrc_init: Physical Base address: 0x%x\n", (u32) IIC_ADDR[instance] )); - iic_ibmocp_adaps[instance]->iic_base = (u32)ioremap((unsigned long)IIC_ADDR[instance],PAGE_SIZE); - - DEB(printk("iic_hw_resrc_init: ioremapped base address: 0x%x\n", iic_ibmocp_adaps[instance]->iic_base)); - - if (iic_ibmocp_adaps[instance]->iic_irq > 0) { - - if (request_irq(iic_ibmocp_adaps[instance]->iic_irq, iic_ibmocp_handler, - 0, "IBM OCP IIC", iic_ibmocp_adaps[instance]) < 0) { - printk(KERN_ERR "iic_hw_resrc_init: Request irq%d failed\n", - iic_ibmocp_adaps[instance]->iic_irq); - iic_ibmocp_adaps[instance]->iic_irq = 0; - } else { - DEB3(printk("iic_hw_resrc_init: Enabled interrupt\n")); - } - } - return 0; -} - - -// -// Description: Release irq and memory -// -static void iic_ibmocp_release(void) -{ - int i; - - for(i=0; i<IIC_NUMS; i++) { - struct iic_ibm *priv_data = (struct iic_ibm *)iic_ibmocp_data[i]->data; - if (priv_data->iic_irq > 0) { - disable_irq(priv_data->iic_irq); - free_irq(priv_data->iic_irq, 0); - } - kfree(iic_ibmocp_data[i]); - kfree(iic_ibmocp_ops[i]); - } -} - - -// -// Description: Called when the module is loaded. This function starts the -// cascade of calls up through the heirarchy of i2c modules (i.e. up to the -// algorithm layer and into to the core layer) -// -static int __init iic_ibmocp_init(void) -{ - int i; - - printk(KERN_INFO "iic_ibmocp_init: IBM on-chip iic adapter module\n"); - - for(i=0; i<IIC_NUMS; i++) { - iic_ibmocp_data[i] = kmalloc(sizeof(struct i2c_algo_iic_data),GFP_KERNEL); - if(iic_ibmocp_data[i] == NULL) { - return -ENOMEM; - } - memset(iic_ibmocp_data[i], 0, sizeof(struct i2c_algo_iic_data)); - - switch (i) { - case 0: - iic_ibmocp_adaps[i]->iic_irq = IIC_IRQ(0); - break; - case 1: - iic_ibmocp_adaps[i]->iic_irq = IIC_IRQ(1); - break; - } - iic_ibmocp_adaps[i]->iic_clock = IIC_CLOCK; - iic_ibmocp_adaps[i]->iic_own = IIC_OWN; - iic_ibmocp_adaps[i]->index = i; - - DEB(printk("irq %x\n", iic_ibmocp_adaps[i]->iic_irq)); - DEB(printk("clock %x\n", iic_ibmocp_adaps[i]->iic_clock)); - DEB(printk("own %x\n", iic_ibmocp_adaps[i]->iic_own)); - DEB(printk("index %x\n", iic_ibmocp_adaps[i]->index)); - - - iic_ibmocp_data[i]->data = (struct iic_regs *)iic_ibmocp_adaps[i]; - iic_ibmocp_data[i]->setiic = iic_ibmocp_setbyte; - iic_ibmocp_data[i]->getiic = iic_ibmocp_getbyte; - iic_ibmocp_data[i]->getown = iic_ibmocp_getown; - iic_ibmocp_data[i]->getclock = iic_ibmocp_getclock; - iic_ibmocp_data[i]->waitforpin = iic_ibmocp_waitforpin; - iic_ibmocp_data[i]->udelay = 80; - iic_ibmocp_data[i]->mdelay = 80; - iic_ibmocp_data[i]->timeout = HZ; - - iic_ibmocp_ops[i] = kmalloc(sizeof(struct i2c_adapter), GFP_KERNEL); - if(iic_ibmocp_ops[i] == NULL) { - return -ENOMEM; - } - memset(iic_ibmocp_ops[i], 0, sizeof(struct i2c_adapter)); - strcpy(iic_ibmocp_ops[i]->name, "IBM OCP IIC adapter"); - iic_ibmocp_ops[i]->owner = THIS_MODULE; - iic_ibmocp_ops[i]->id = I2C_HW_OCP; - iic_ibmocp_ops[i]->algo = NULL; - iic_ibmocp_ops[i]->algo_data = iic_ibmocp_data[i]; - - - init_waitqueue_head(&(iic_wait[i])); - if (iic_hw_resrc_init(i) == 0) { - if (i2c_ocp_add_bus(iic_ibmocp_ops[i]) < 0) - return -ENODEV; - } else { - return -ENODEV; - } - DEB(printk(KERN_INFO "iic_ibmocp_init: found device at %#x.\n\n", iic_ibmocp_adaps[i]->iic_base)); - } - return 0; -} - - -static void __exit iic_ibmocp_exit(void) -{ - int i; - - for(i=0; i<IIC_NUMS; i++) { - i2c_ocp_del_bus(iic_ibmocp_ops[i]); - } - iic_ibmocp_release(); -} - -// -// If modules is NOT defined when this file is compiled, then the MODULE_* -// macros will resolve to nothing -// -MODULE_AUTHOR("MontaVista Software <www.mvista.com>"); -MODULE_DESCRIPTION("I2C-Bus adapter routines for PPC 405 IIC bus adapter"); -MODULE_LICENSE("GPL"); - -MODULE_PARM(base, "i"); -MODULE_PARM(irq, "i"); -MODULE_PARM(clock, "i"); -MODULE_PARM(own, "i"); -MODULE_PARM(i2c_debug,"i"); - - -module_init(iic_ibmocp_init); -module_exit(iic_ibmocp_exit); diff -N -u2 -r i2c-orig/kernel/i2c-algo-ibm_ocp.c i2c/kernel/i2c-algo-ibm_ocp.c --- i2c-orig/kernel/i2c-algo-ibm_ocp.c 2003-01-21 01:08:16.000000000 -0700 +++ i2c/kernel/i2c-algo-ibm_ocp.c 1969-12-31 17:00:00.000000000 -0700 @@ -1,901 +0,0 @@ -/* - ------------------------------------------------------------------------- - i2c-algo-ibm_ocp.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. - --------------------------------------------------------------------------- - - History: 01/20/12 - Armin - akuster at mvista.com - ported up to 2.4.16+ - - Version 02/03/25 - Armin - converted to ocp format - removed commented out or #if 0 code - added G?rard Basler's fix to iic_combined_transaction() such that it - returns the number of successfully completed transfers . -*/ - - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/delay.h> -#include <linux/slab.h> -#include <linux/init.h> -#include <linux/errno.h> -#include <linux/sched.h> -#include "i2c.h" -#include "i2c-algo-ibm_ocp.h" -#include <asm/ocp.h> - - -/* ----- global defines ----------------------------------------------- */ -#define DEB(x) if (i2c_debug>=1) x -#define DEB2(x) if (i2c_debug>=2) x -#define DEB3(x) if (i2c_debug>=3) x /* print several statistical values*/ -#define DEBPROTO(x) if (i2c_debug>=9) x; - /* debug the protocol by showing transferred bits */ -#define DEF_TIMEOUT 5 - - -/* ----- global variables --------------------------------------------- */ - - -/* module parameters: - */ -static int i2c_debug=0; - -/* --- setting states on the bus with the right timing: --------------- */ - -#define iic_outb(adap, reg, val) adap->setiic(adap->data, (int) &(reg), val) -#define iic_inb(adap, reg) adap->getiic(adap->data, (int) &(reg)) - -#define IICO_I2C_SDAHIGH 0x0780 -#define IICO_I2C_SDALOW 0x0781 -#define IICO_I2C_SCLHIGH 0x0782 -#define IICO_I2C_SCLLOW 0x0783 -#define IICO_I2C_LINEREAD 0x0784 - -#define IIC_SINGLE_XFER 0 -#define IIC_COMBINED_XFER 1 - -#define IIC_ERR_LOST_ARB -2 -#define IIC_ERR_INCOMPLETE_XFR -3 -#define IIC_ERR_NACK -1 - -/* --- other auxiliary functions -------------------------------------- */ - - -// -// Description: Puts this process to sleep for a period equal to timeout -// -static inline void iic_sleep(unsigned long timeout) -{ - schedule_timeout( timeout * HZ); -} - - -// -// Description: This performs the IBM PPC 405 IIC initialization sequence -// as described in the PPC405GP data book. -// -static int iic_init (struct i2c_algo_iic_data *adap) -{ - struct iic_regs *iic; - struct iic_ibm *adap_priv_data = adap->data; - unsigned short retval; - iic = (struct iic_regs *) adap_priv_data->iic_base; - - /* Clear master low master address */ - iic_outb(adap,iic->lmadr, 0); - - /* Clear high master address */ - iic_outb(adap,iic->hmadr, 0); - - /* Clear low slave address */ - iic_outb(adap,iic->lsadr, 0); - - /* Clear high slave address */ - iic_outb(adap,iic->hsadr, 0); - - /* Clear status */ - iic_outb(adap,iic->sts, 0x0a); - - /* Clear extended status */ - iic_outb(adap,iic->extsts, 0x8f); - - /* Set clock division */ - iic_outb(adap,iic->clkdiv, 0x04); - - retval = iic_inb(adap, iic->clkdiv); - DEB(printk("iic_init: CLKDIV register = %x\n", retval)); - - /* Enable interrupts on Requested Master Transfer Complete */ - iic_outb(adap,iic->intmsk, 0x01); - - /* Clear transfer count */ - iic_outb(adap,iic->xfrcnt, 0x0); - - /* Clear extended control and status */ - iic_outb(adap,iic->xtcntlss, 0xf0); - - /* Set mode control (flush master data buf, enable hold SCL, exit */ - /* unknown state. */ - iic_outb(adap,iic->mdcntl, 0x47); - - /* Clear control register */ - iic_outb(adap,iic->cntl, 0x0); - - DEB2(printk(KERN_DEBUG "iic_init: Initialized IIC on PPC 405\n")); - return 0; -} - - -// -// Description: After we issue a transaction on the IIC bus, this function -// is called. It puts this process to sleep until we get an interrupt from -// from the controller telling us that the transaction we requested in complete. -// -static int wait_for_pin(struct i2c_algo_iic_data *adap, int *status) -{ - - int timeout = DEF_TIMEOUT; - int retval; - struct iic_regs *iic; - struct iic_ibm *adap_priv_data = adap->data; - iic = (struct iic_regs *) adap_priv_data->iic_base; - - - *status = iic_inb(adap, iic->sts); -#ifndef STUB_I2C - - while (timeout-- && (*status & 0x01)) { - adap->waitforpin(adap->data); - *status = iic_inb(adap, iic->sts); - } -#endif - if (timeout <= 0) { - /* Issue stop signal on the bus, and force an interrupt */ - retval = iic_inb(adap, iic->cntl); - iic_outb(adap, iic->cntl, retval | 0x80); - /* Clear status register */ - iic_outb(adap, iic->sts, 0x0a); - /* Exit unknown bus state */ - retval = iic_inb(adap, iic->mdcntl); - iic_outb(adap, iic->mdcntl, (retval | 0x02)); - - // Check the status of the controller. Does it still see a - // pending transfer, even though we've tried to stop any - // ongoing transaction? - retval = iic_inb(adap, iic->sts); - retval = retval & 0x01; - if(retval) { - // The iic controller is hosed. It is not responding to any - // of our commands. We have already tried to force it into - // a known state, but it has not worked. Our only choice now - // is a soft reset, which will clear all registers, and force - // us to re-initialize the controller. - /* Soft reset */ - iic_outb(adap, iic->xtcntlss, 0x01); - udelay(500); - iic_init(adap); - /* Is the pending transfer bit in the sts reg finally cleared? */ - retval = iic_inb(adap, iic->sts); - retval = retval & 0x01; - if(retval) { - printk(KERN_CRIT "The IIC Controller is hosed. A processor reset is required\n"); - } - // For some reason, even though the interrupt bit in this - // register was set during iic_init, it didn't take. We - // need to set it again. Don't ask me why....this is just what - // I saw when testing timeouts. - iic_outb(adap, iic->intmsk, 0x01); - } - return(-1); - } - else - return(0); -} - - -//------------------------------------ -// Utility functions -// - - -// -// Description: Look at the status register to see if there was an error -// in the requested transaction. If there is, look at the extended status -// register and determine the exact cause. -// -int analyze_status(struct i2c_algo_iic_data *adap, int *error_code) -{ - int ret; - struct iic_regs *iic; - struct iic_ibm *adap_priv_data = adap->data; - iic = (struct iic_regs *) adap_priv_data->iic_base; - - - ret = iic_inb(adap, iic->sts); - if(ret & 0x04) { - // Error occurred - ret = iic_inb(adap, iic->extsts); - if(ret & 0x04) { - // Lost arbitration - *error_code = IIC_ERR_LOST_ARB; - } - if(ret & 0x02) { - // Incomplete transfer - *error_code = IIC_ERR_INCOMPLETE_XFR; - } - if(ret & 0x01) { - // Master transfer aborted by a NACK during the transfer of the - // address byte - *error_code = IIC_ERR_NACK; - } - return -1; - } - return 0; -} - - -// -// Description: This function is called by the upper layers to do the -// grunt work for a master send transaction -// -static int iic_sendbytes(struct i2c_adapter *i2c_adap,const char *buf, - int count, int xfer_flag) -{ - struct iic_regs *iic; - struct i2c_algo_iic_data *adap = i2c_adap->algo_data; - struct iic_ibm *adap_priv_data = adap->data; - int wrcount, status, timeout; - int loops, remainder, i, j; - int ret, error_code; - iic = (struct iic_regs *) adap_priv_data->iic_base; - - - if( count == 0 ) return 0; - wrcount = 0; - loops = count / 4; - remainder = count % 4; - - if((loops > 1) && (remainder == 0)) { - for(i=0; i<(loops-1); i++) { - // - // Write four bytes to master data buffer - // - for(j=0; j<4; j++) { - iic_outb(adap, iic->mdbuf, - buf[wrcount++]); - } - // - // Issue command to IICO device to begin transmission - // - iic_outb(adap, iic->cntl, 0x35); - // - // Wait for transmission to complete. When it does, - //loop to the top of the for statement and write the - // next four bytes. - // - timeout = wait_for_pin(adap, &status); - if(timeout < 0) { - // - // Error handling - // - //printk(KERN_ERR "Error: write timeout\n"); - return wrcount; - } - ret = analyze_status(adap, &error_code); - if(ret < 0) { - if(error_code == IIC_ERR_INCOMPLETE_XFR) { - // Return the number of bytes transferred - ret = iic_inb(adap, iic->xfrcnt); - ret = ret & 0x07; - return (wrcount-4+ret); - } - else return error_code; - } - } - } - else if((loops >= 1) && (remainder > 0)){ - //printk(KERN_DEBUG "iic_sendbytes: (loops >= 1)\n"); - for(i=0; i<loops; i++) { - // - // Write four bytes to master data buffer - // - for(j=0; j<4; j++) { - iic_outb(adap, iic->mdbuf, - buf[wrcount++]); - } - // - // Issue command to IICO device to begin transmission - // - iic_outb(adap, iic->cntl, 0x35); - // - // Wait for transmission to complete. When it does, - //loop to the top of the for statement and write the - // next four bytes. - // - timeout = wait_for_pin(adap, &status); - if(timeout < 0) { - // - // Error handling - // - //printk(KERN_ERR "Error: write timeout\n"); - return wrcount; - } - ret = analyze_status(adap, &error_code); - if(ret < 0) { - if(error_code == IIC_ERR_INCOMPLETE_XFR) { - // Return the number of bytes transferred - ret = iic_inb(adap, iic->xfrcnt); - ret = ret & 0x07; - return (wrcount-4+ret); - } - else return error_code; - } - } - } - - //printk(KERN_DEBUG "iic_sendbytes: expedite write\n"); - if(remainder == 0) remainder = 4; - // remainder = remainder - 1; - // - // Write the remaining bytes (less than or equal to 4) - // - for(i=0; i<remainder; i++) { - iic_outb(adap, iic->mdbuf, buf[wrcount++]); - //printk(KERN_DEBUG "iic_sendbytes: data transferred = %x, wrcount = %d\n", buf[wrcount-1], (wrcount-1)); - } - //printk(KERN_DEBUG "iic_sendbytes: Issuing write\n"); - - if(xfer_flag == IIC_COMBINED_XFER) { - iic_outb(adap, iic->cntl, (0x09 | ((remainder-1) << 4))); - } - else { - iic_outb(adap, iic->cntl, (0x01 | ((remainder-1) << 4))); - } - DEB2(printk(KERN_DEBUG "iic_sendbytes: Waiting for interrupt\n")); - timeout = wait_for_pin(adap, &status); - if(timeout < 0) { - // - // Error handling - // - //printk(KERN_ERR "Error: write timeout\n"); - return wrcount; - } - ret = analyze_status(adap, &error_code); - if(ret < 0) { - if(error_code == IIC_ERR_INCOMPLETE_XFR) { - // Return the number of bytes transferred - ret = iic_inb(adap, iic->xfrcnt); - ret = ret & 0x07; - return (wrcount-4+ret); - } - else return error_code; - } - DEB2(printk(KERN_DEBUG "iic_sendbytes: Got interrupt\n")); - return wrcount; -} - - -// -// Description: Called by the upper layers to do the grunt work for -// a master read transaction. -// -static int iic_readbytes(struct i2c_adapter *i2c_adap, char *buf, int count, int xfer_type) -{ - struct iic_regs *iic; - int rdcount=0, i, status, timeout; - struct i2c_algo_iic_data *adap = i2c_adap->algo_data; - struct iic_ibm *adap_priv_data = adap->data; - int loops, remainder, j; - int ret, error_code; - iic = (struct iic_regs *) adap_priv_data->iic_base; - - if(count == 0) return 0; - loops = count / 4; - remainder = count % 4; - - //printk(KERN_DEBUG "iic_readbytes: loops = %d, remainder = %d\n", loops, remainder); - - if((loops > 1) && (remainder == 0)) { - //printk(KERN_DEBUG "iic_readbytes: (loops > 1) && (remainder == 0)\n"); - for(i=0; i<(loops-1); i++) { - // - // Issue command to begin master read (4 bytes maximum) - // - //printk(KERN_DEBUG "--->Issued read command\n"); - iic_outb(adap, iic->cntl, 0x37); - // - // Wait for transmission to complete. When it does, - // loop to the top of the for statement and write the - // next four bytes. - // - //printk(KERN_DEBUG "--->Waiting for interrupt\n"); - timeout = wait_for_pin(adap, &status); - if(timeout < 0) { - // Error Handler - //printk(KERN_ERR "Error: read timed out\n"); - return rdcount; - } - //printk(KERN_DEBUG "--->Got interrupt\n"); - - ret = analyze_status(adap, &error_code); - if(ret < 0) { - if(error_code == IIC_ERR_INCOMPLETE_XFR) - return rdcount; - else - return error_code; - } - - for(j=0; j<4; j++) { - // Wait for data to shuffle to top of data buffer - // This value needs to optimized. - udelay(1); - buf[rdcount] = iic_inb(adap, iic->mdbuf); - rdcount++; - //printk(KERN_DEBUG "--->Read one byte\n"); - } - } - } - - else if((loops >= 1) && (remainder > 0)){ - //printk(KERN_DEBUG "iic_readbytes: (loops >=1) && (remainder > 0)\n"); - for(i=0; i<loops; i++) { - // - // Issue command to begin master read (4 bytes maximum) - // - //printk(KERN_DEBUG "--->Issued read command\n"); - iic_outb(adap, iic->cntl, 0x37); - // - // Wait for transmission to complete. When it does, - // loop to the top of the for statement and write the - // next four bytes. - // - //printk(KERN_DEBUG "--->Waiting for interrupt\n"); - timeout = wait_for_pin(adap, &status); - if(timeout < 0) { - // Error Handler - //printk(KERN_ERR "Error: read timed out\n"); - return rdcount; - } - //printk(KERN_DEBUG "--->Got interrupt\n"); - - ret = analyze_status(adap, &error_code); - if(ret < 0) { - if(error_code == IIC_ERR_INCOMPLETE_XFR) - return rdcount; - else - return error_code; - } - - for(j=0; j<4; j++) { - // Wait for data to shuffle to top of data buffer - // This value needs to optimized. - udelay(1); - buf[rdcount] = iic_inb(adap, iic->mdbuf); - rdcount++; - //printk(KERN_DEBUG "--->Read one byte\n"); - } - } - } - - //printk(KERN_DEBUG "iic_readbytes: expedite read\n"); - if(remainder == 0) remainder = 4; - DEB2(printk(KERN_DEBUG "iic_readbytes: writing %x to IICO_CNTL\n", (0x03 | ((remainder-1) << 4)))); - - if(xfer_type == IIC_COMBINED_XFER) { - iic_outb(adap, iic->cntl, (0x0b | ((remainder-1) << 4))); - } - else { - iic_outb(adap, iic->cntl, (0x03 | ((remainder-1) << 4))); - } - DEB2(printk(KERN_DEBUG "iic_readbytes: Wait for pin\n")); - timeout = wait_for_pin(adap, &status); - DEB2(printk(KERN_DEBUG "iic_readbytes: Got the interrupt\n")); - if(timeout < 0) { - // Error Handler - //printk(KERN_ERR "Error: read timed out\n"); - return rdcount; - } - - ret = analyze_status(adap, &error_code); - if(ret < 0) { - if(error_code == IIC_ERR_INCOMPLETE_XFR) - return rdcount; - else - return error_code; - } - - //printk(KERN_DEBUG "iic_readbyte: Begin reading data buffer\n"); - for(i=0; i<remainder; i++) { - buf[rdcount] = iic_inb(adap, iic->mdbuf); - // printk(KERN_DEBUG "iic_readbytes: Character read = %x\n", buf[rdcount]); - rdcount++; - } - - return rdcount; -} - - -// -// Description: This function implements combined transactions. Combined -// transactions consist of combinations of reading and writing blocks of data. -// Each transfer (i.e. a read or a write) is separated by a repeated start -// condition. -// -static int iic_combined_transaction(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num) -{ - int i; - struct i2c_msg *pmsg; - int ret; - - DEB2(printk(KERN_DEBUG "Beginning combined transaction\n")); - for(i=0; i < num; i++) { - pmsg = &msgs[i]; - if(pmsg->flags & I2C_M_RD) { - - // Last read or write segment needs to be terminated with a stop - if(i < num-1) { - DEB2(printk(KERN_DEBUG "This one is a read\n")); - } - else { - DEB2(printk(KERN_DEBUG "Doing the last read\n")); - } - ret = iic_readbytes(i2c_adap, pmsg->buf, pmsg->len, (i < num-1) ? IIC_COMBINED_XFER : IIC_SINGLE_XFER); - - if (ret != pmsg->len) { - DEB2(printk("i2c-algo-ppc405.o: fail: " - "only read %d bytes.\n",ret)); - return i; - } - else { - DEB2(printk("i2c-algo-ppc405.o: read %d bytes.\n",ret)); - } - } - else if(!(pmsg->flags & I2C_M_RD)) { - - // Last read or write segment needs to be terminated with a stop - if(i < num-1) { - DEB2(printk(KERN_DEBUG "This one is a write\n")); - } - else { - DEB2(printk(KERN_DEBUG "Doing the last write\n")); - } - ret = iic_sendbytes(i2c_adap, pmsg->buf, pmsg->len, (i < num-1) ? IIC_COMBINED_XFER : IIC_SINGLE_XFER); - - if (ret != pmsg->len) { - DEB2(printk("i2c-algo-ppc405.o: fail: " - "only wrote %d bytes.\n",ret)); - return i; - } - else { - DEB2(printk("i2c-algo-ppc405.o: wrote %d bytes.\n",ret)); - } - } - } - - return num; -} - - -// -// Description: Whenever we initiate a transaction, the first byte clocked -// onto the bus after the start condition is the address (7 bit) of the -// device we want to talk to. This function manipulates the address specified -// so that it makes sense to the hardware when written to the IIC peripheral. -// -// Note: 10 bit addresses are not supported in this driver, although they are -// supported by the hardware. This functionality needs to be implemented. -// -static inline int iic_doAddress(struct i2c_algo_iic_data *adap, - struct i2c_msg *msg, int retries) -{ - struct iic_regs *iic; - unsigned short flags = msg->flags; - unsigned char addr; - struct iic_ibm *adap_priv_data = adap->data; - iic = (struct iic_regs *) adap_priv_data->iic_base; - -// -// The following segment for 10 bit addresses needs to be ported -// -/* Ten bit addresses not supported right now - if ( (flags & I2C_M_TEN) ) { - // a ten bit address - addr = 0xf0 | (( msg->addr >> 7) & 0x03); - DEB2(printk(KERN_DEBUG "addr0: %d\n",addr)); - // try extended address code... - ret = try_address(adap, addr, retries); - if (ret!=1) { - printk(KERN_ERR "iic_doAddress: died at extended address code.\n"); - return -EREMOTEIO; - } - // the remaining 8 bit address - iic_outb(adap,msg->addr & 0x7f); - // Status check comes here - if (ret != 1) { - printk(KERN_ERR "iic_doAddress: died at 2nd address code.\n"); - return -EREMOTEIO; - } - if ( flags & I2C_M_RD ) { - i2c_repstart(adap); - // okay, now switch into reading mode - addr |= 0x01; - ret = try_address(adap, addr, retries); - if (ret!=1) { - printk(KERN_ERR "iic_doAddress: died at extended address code.\n"); - return -EREMOTEIO; - } - } - } else ----------> // normal 7 bit address - -Ten bit addresses not supported yet */ - - addr = ( msg->addr << 1 ); - if (flags & I2C_M_RD ) - addr |= 1; - if (flags & I2C_M_REV_DIR_ADDR ) - addr ^= 1; - // - // Write to the low slave address - // - iic_outb(adap, iic->lmadr, addr); - // - // Write zero to the high slave register since we are - // only using 7 bit addresses - // - iic_outb(adap, iic->hmadr, 0); - - return 0; -} - - -// -// Description: Prepares the controller for a transaction (clearing status -// registers, data buffers, etc), and then calls either iic_readbytes or -// iic_sendbytes to do the actual transaction. -// -static int iic_xfer(struct i2c_adapter *i2c_adap, - struct i2c_msg msgs[], - int num) -{ - struct iic_regs *iic; - struct i2c_algo_iic_data *adap = i2c_adap->algo_data; - struct iic_ibm *adap_priv_data = adap->data; - struct i2c_msg *pmsg; - int i = 0; - int ret; - iic = (struct iic_regs *) adap_priv_data->iic_base; - - pmsg = &msgs[i]; - - // - // Clear status register - // - DEB2(printk(KERN_DEBUG "iic_xfer: iic_xfer: Clearing status register\n")); - iic_outb(adap, iic->sts, 0x0a); - - // - // Wait for any pending transfers to complete - // - DEB2(printk(KERN_DEBUG "iic_xfer: Waiting for any pending transfers to complete\n")); - while((ret = iic_inb(adap, iic->sts)) == 0x01) { - ; - } - - // - // Flush master data buf - // - DEB2(printk(KERN_DEBUG "iic_xfer: Clearing master data buffer\n")); - ret = iic_inb(adap, iic->mdcntl); - iic_outb(adap, iic->mdcntl, ret | 0x40); - - // - // Load slave address - // - DEB2(printk(KERN_DEBUG "iic_xfer: Loading slave address\n")); - ret = iic_doAddress(adap, pmsg, i2c_adap->retries); - - // - // Check to see if the bus is busy - // - ret = iic_inb(adap, iic->extsts); - // Mask off the irrelevent bits - ret = ret & 0x70; - // When the bus is free, the BCS bits in the EXTSTS register are 0b100 - if(ret != 0x40) return IIC_ERR_LOST_ARB; - - // - // Combined transaction (read and write) - // - if(num > 1) { - DEB2(printk(KERN_DEBUG "iic_xfer: Call combined transaction\n")); - ret = iic_combined_transaction(i2c_adap, msgs, num); - } - // - // Read only - // - else if((num == 1) && (pmsg->flags & I2C_M_RD)) { - // - // Tell device to begin reading data from the master data - // - DEB2(printk(KERN_DEBUG "iic_xfer: Call adapter's read\n")); - ret = iic_readbytes(i2c_adap, pmsg->buf, pmsg->len, IIC_SINGLE_XFER); - } - // - // Write only - // - else if((num == 1 ) && (!(pmsg->flags & I2C_M_RD))) { - // - // Write data to master data buffers and tell our device - // to begin transmitting - // - DEB2(printk(KERN_DEBUG "iic_xfer: Call adapter's write\n")); - ret = iic_sendbytes(i2c_adap, pmsg->buf, pmsg->len, IIC_SINGLE_XFER); - } - - return ret; -} - - -// -// Description: Implements device specific ioctls. Higher level ioctls can -// be found in i2c-core.c and are typical of any i2c controller (specifying -// slave address, timeouts, etc). These ioctls take advantage of any hardware -// features built into the controller for which this algorithm-adapter set -// was written. These ioctls allow you to take control of the data and clock -// lines on the IBM PPC 405 IIC controller and set the either high or low, -// similar to a GPIO pin. -// -static int algo_control(struct i2c_adapter *adapter, - unsigned int cmd, unsigned long arg) -{ - struct iic_regs *iic; - struct i2c_algo_iic_data *adap = adapter->algo_data; - struct iic_ibm *adap_priv_data = adap->data; - int ret=0; - int lines; - iic = (struct iic_regs *) adap_priv_data->iic_base; - - lines = iic_inb(adap, iic->directcntl); - - if (cmd == IICO_I2C_SDAHIGH) { - lines = lines & 0x01; - if( lines ) lines = 0x04; - else lines = 0; - iic_outb(adap, iic->directcntl,(0x08|lines)); - } - else if (cmd == IICO_I2C_SDALOW) { - lines = lines & 0x01; - if( lines ) lines = 0x04; - else lines = 0; - iic_outb(adap, iic->directcntl,(0x00|lines)); - } - else if (cmd == IICO_I2C_SCLHIGH) { - lines = lines & 0x02; - if( lines ) lines = 0x08; - else lines = 0; - iic_outb(adap, iic->directcntl,(0x04|lines)); - } - else if (cmd == IICO_I2C_SCLLOW) { - lines = lines & 0x02; - if( lines ) lines = 0x08; - else lines = 0; - iic_outb(adap, iic->directcntl,(0x00|lines)); - } - else if (cmd == IICO_I2C_LINEREAD) { - ret = lines; - } - return ret; -} - - -static u32 iic_func(struct i2c_adapter *adap) -{ - return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR | - I2C_FUNC_PROTOCOL_MANGLING; -} - - -/* -----exported algorithm data: ------------------------------------- */ - -static struct i2c_algorithm iic_algo = { - .owner = THIS_MODULE, - .name = "IBM on-chip IIC algorithm", - .id = I2C_ALGO_OCP, - .master_xfer = iic_xfer, - .algo_control = algo_control, - .functionality = iic_func, -}; - -/* - * registering functions to load algorithms at runtime - */ - - -// -// Description: Register bus structure -// -int i2c_ocp_add_bus(struct i2c_adapter *adap) -{ - struct i2c_algo_iic_data *iic_adap = adap->algo_data; - - DEB2(printk(KERN_DEBUG "i2c-algo-iic.o: hw routines for %s registered.\n", - adap->name)); - - /* register new adapter to i2c module... */ - - adap->id |= iic_algo.id; - adap->algo = &iic_algo; - - adap->timeout = 100; /* default values, should */ - adap->retries = 3; /* be replaced by defines */ - - iic_init(iic_adap); - i2c_add_adapter(adap); - return 0; -} - - -// -// Done -// -int i2c_ocp_del_bus(struct i2c_adapter *adap) -{ - return i2c_del_adapter(adap); -} - - -EXPORT_SYMBOL(i2c_ocp_add_bus); -EXPORT_SYMBOL(i2c_ocp_del_bus); - -// -// The MODULE_* macros resolve to nothing if MODULES is not defined -// when this file is compiled. -// -MODULE_AUTHOR("MontaVista Software <www.mvista.com>"); -MODULE_DESCRIPTION("PPC 405 iic algorithm"); -MODULE_LICENSE("GPL"); - -MODULE_PARM(i2c_debug,"i"); - -MODULE_PARM_DESC(i2c_debug, - "debug level - 0 off; 1 normal; 2,3 more verbose; 9 iic-protocol"); - diff -N -u2 -r i2c-orig/kernel/i2c-algo-ibm_ocp.h i2c/kernel/i2c-algo-ibm_ocp.h --- i2c-orig/kernel/i2c-algo-ibm_ocp.h 2003-01-21 01:08:16.000000000 -0700 +++ i2c/kernel/i2c-algo-ibm_ocp.h 1969-12-31 17:00:00.000000000 -0700 @@ -1,52 +0,0 @@ -/* ------------------------------------------------------------------------- */ -/* i2c-algo-ibm_ocp.h i2c driver algorithms for IBM PPC 405 IIC adapters */ -/* ------------------------------------------------------------------------- */ -/* Copyright (C) 1995-97 Simon G. Vogl - 1998-99 Hans Berglund - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* ------------------------------------------------------------------------- */ - -/* With some changes from Ky?sti M?lkki <kmalkki 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 */ - -#ifndef _LINUX_I2C_ALGO_IBM_OCP_H -#define _LINUX_I2C_ALGO_IBM_OCP_H - -struct i2c_algo_iic_data { - struct iic_regs *data; /* private data for lolevel routines */ - void (*setiic) (void *data, int ctl, int val); - int (*getiic) (void *data, int ctl); - int (*getown) (void *data); - int (*getclock) (void *data); - void (*waitforpin) (void *data); - - /* local settings */ - int udelay; - int mdelay; - int timeout; -}; - - -#define I2C_IIC_ADAP_MAX 16 - - -int i2c_ocp_add_bus(struct i2c_adapter *); -int i2c_ocp_del_bus(struct i2c_adapter *); - -#endif /* _LINUX_I2C_ALGO_IBM_OCP_H */ diff -N -u2 -r i2c-orig/kernel/i2c-ibm_iic.c i2c/kernel/i2c-ibm_iic.c --- i2c-orig/kernel/i2c-ibm_iic.c 1969-12-31 17:00:00.000000000 -0700 +++ i2c/kernel/i2c-ibm_iic.c 2003-09-12 16:10:29.000000000 -0700 @@ -0,0 +1,733 @@ +/* + * drivers/i2c/i2c-ibm_iic.c + * + * Support for the IIC peripheral on IBM PPC 4xx + * + * Copyright (c) 2003 Zultys Technologies. + * Eugene Surovegin <eugene.surovegin at zultys.com> or <ebs at ebshome.net> + * + * Based on original work by + * Ian DaSilva <idasilva at mvista.com> + * Armin Kuster <akuster at mvista.com> + * Matt Porter <mporter at mvista.com> + * + * Copyright 2000-2003 MontaVista Software Inc. + * + * Original driver version was highly leveraged from i2c-elektor.c + * + * Copyright 1995-97 Simon G. Vogl + * 1998-99 Hans Berglund + * + * With some changes from Ky?sti M?lkki <kmalkki 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. + * + */ +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/ioport.h> +#include <linux/delay.h> +#include <linux/slab.h> +#include <linux/init.h> +#include <asm/irq.h> +#include <asm/io.h> +#include <linux/i2c.h> +#include <linux/i2c-id.h> +#include <asm/ocp.h> + +#include "i2c-ibm_iic.h" + +#define DRIVER_VERSION "2.0" + +MODULE_DESCRIPTION("IBM IIC driver v" DRIVER_VERSION); +MODULE_LICENSE("GPL"); + +static int iic_scan = 0; +MODULE_PARM(iic_scan, "i"); +MODULE_PARM_DESC(iic_scan, "Scan for active chips on the bus"); + +static int iic_force_poll = 0; +MODULE_PARM(iic_force_poll, "i"); +MODULE_PARM_DESC(iic_force_poll, "Force polling mode"); + +static int iic_force_fast = 0; +MODULE_PARM(iic_force_fast, "i"); +MODULE_PARM_DESC(iic_fast_poll, "Force fast mode (400 kHz)"); + +#define DBG_LEVEL 0 + +#if DBG_LEVEL > 0 +# define DBG(x...) printk(KERN_DEBUG "ibm-iic" ##x) +#else +# define DBG(x...) ((void)0) +#endif +#if DBG_LEVEL > 1 +# define DBG2(x...) DBG( ##x ) +#else +# define DBG2(x...) ((void)0) +#endif +#if DBG_LEVEL > 2 +static void dump_iic_regs(const char* header, struct ibm_iic_private* dev) +{ + volatile struct iic_regs *iic = dev->vaddr; + printk(KERN_DEBUG "ibm-iic%d: %s\n", dev->idx, header); + printk(KERN_DEBUG " cntl = 0x%02x, mdcntl = 0x%02x\n" + KERN_DEBUG " sts = 0x%02x, extsts = 0x%02x\n" + KERN_DEBUG " clkdiv = 0x%02x, xfrcnt = 0x%02x\n" + KERN_DEBUG " xtcntlss = 0x%02x, directcntl = 0x%02x\n", + in_8(&iic->cntl), in_8(&iic->mdcntl), in_8(&iic->sts), + in_8(&iic->extsts), in_8(&iic->clkdiv), in_8(&iic->xfrcnt), + in_8(&iic->xtcntlss), in_8(&iic->directcntl)); +} +# define DUMP_REGS(h,dev) dump_iic_regs((h),(dev)) +#else +# define DUMP_REGS(h,dev) ((void)0) +#endif + +/* Enable/disable interrupt generation */ +static inline void iic_interrupt_mode(struct ibm_iic_private* dev, int enable) +{ + out_8(&dev->vaddr->intmsk, enable ? INTRMSK_EIMTC : 0); +} + +/* + * Initialize IIC interface. + */ +static void iic_dev_init(struct ibm_iic_private* dev) +{ + volatile struct iic_regs *iic = dev->vaddr; + + DBG("%d: init\n", dev->idx); + + /* Clear master address */ + out_8(&iic->lmadr, 0); + out_8(&iic->hmadr, 0); + + /* Clear slave address */ + out_8(&iic->lsadr, 0); + out_8(&iic->hsadr, 0); + + /* Clear status & extended status */ + out_8(&iic->sts, STS_SCMP | STS_IRQA); + out_8(&iic->extsts, EXTSTS_IRQP | EXTSTS_IRQD | EXTSTS_LA + | EXTSTS_ICT | EXTSTS_XFRA); + + /* Set clock divider */ + out_8(&iic->clkdiv, dev->clckdiv); + + /* Clear transfer count */ + out_8(&iic->xfrcnt, 0); + + /* Clear extended control and status */ + out_8(&iic->xtcntlss, XTCNTLSS_SRC | XTCNTLSS_SRS | XTCNTLSS_SWC + | XTCNTLSS_SWS); + + /* Clear control register */ + out_8(&iic->cntl, 0); + + /* Enable interrupts if possible */ + iic_interrupt_mode(dev, dev->irq >= 0); + + /* Set mode control */ + out_8(&iic->mdcntl, MDCNTL_FMDB | MDCNTL_EINT | MDCNTL_EUBS + | (dev->fast_mode ? MDCNTL_FSM : 0)); + + DUMP_REGS("iic_init", dev); +} + +/* + * Reset IIC interface + */ +static void iic_dev_reset(struct ibm_iic_private* dev) +{ + volatile struct iic_regs *iic = dev->vaddr; + int i; + u8 dc; + + DBG("%d: soft reset\n", dev->idx); + DUMP_REGS("reset", dev); + + /* Place chip in the reset state */ + out_8(&iic->xtcntlss, XTCNTLSS_SRST); + + /* Check if bus is free */ + dc = in_8(&iic->directcntl); + if (!DIRCTNL_FREE(dc)){ + DBG("%d: trying to regain bus control\n", dev->idx); + + /* Try to set bus free state */ + out_8(&iic->directcntl, DIRCNTL_SDAC | DIRCNTL_SCC); + + /* Wait until we regain bus control */ + for (i = 0; i < 100; ++i){ + dc = in_8(&iic->directcntl); + if (DIRCTNL_FREE(dc)) + break; + + /* Toggle SCL line */ + dc ^= DIRCNTL_SCC; + out_8(&iic->directcntl, dc); + udelay(10); + dc ^= DIRCNTL_SCC; + out_8(&iic->directcntl, dc); + + /* be nice */ + if (current->need_resched) + schedule(); + } + } + + /* Remove reset */ + out_8(&iic->xtcntlss, 0); + + /* Reinitialize interface */ + iic_dev_init(dev); +} + +/* + * IIC interrupt handler + */ +static void iic_handler(int irq, void *dev_id, struct pt_regs *regs) +{ + struct ibm_iic_private* dev = (struct ibm_iic_private*)dev_id; + volatile struct iic_regs* iic = dev->vaddr; + + DBG2("%d: irq handler, STS = 0x%02x, EXTSTS = 0x%02x\n", + dev->idx, in_8(&iic->sts), in_8(&iic->extsts)); + + /* Acknowledge IRQ and wakeup iic_wait_for_tc */ + out_8(&iic->sts, STS_IRQA | STS_SCMP); + wake_up_interruptible(&dev->wq); +} + +/* + * Get master transfer result and clear errors if any. + * Returns the number of actually transferred bytes or error (<0) + */ +static int iic_xfer_result(struct ibm_iic_private* dev) +{ + volatile struct iic_regs *iic = dev->vaddr; + + if (unlikely(in_8(&iic->sts) & STS_ERR)){ + DBG("%d: xfer error, EXTSTS = 0x%02x\n", dev->idx, + in_8(&iic->extsts)); + + /* Clear errors and possible pending IRQs */ + out_8(&iic->extsts, EXTSTS_IRQP | EXTSTS_IRQD | + EXTSTS_LA | EXTSTS_ICT | EXTSTS_XFRA); + + /* Flush master data buffer */ + out_8(&iic->mdcntl, in_8(&iic->mdcntl) | MDCNTL_FMDB); + + /* Is bus free? + * If error happened during combined xfer + * IIC interface is usually stuck in some strange + * state, the only way out - soft reset. + */ + if ((in_8(&iic->extsts) & EXTSTS_BCS_MASK) != EXTSTS_BCS_FREE){ + DBG("%d: bus is stuck, resetting\n", dev->idx); + iic_dev_reset(dev); + } + return -EREMOTEIO; + } + else + return in_8(&iic->xfrcnt) & XFRCNT_MTC_MASK; +} + +/* + * Try to abort active transfer. + */ +static void iic_abort_xfer(struct ibm_iic_private* dev) +{ + volatile struct iic_regs *iic = dev->vaddr; + unsigned long x; + + DBG("%d: iic_abort_xfer\n", dev->idx); + + out_8(&iic->cntl, CNTL_HMT); + + /* + * Wait for the abort command to complete. + * It's not worth to be optimized, just poll (timeout >= 1 tick) + */ + x = jiffies + 2; + while ((in_8(&iic->extsts) & EXTSTS_BCS_MASK) != EXTSTS_BCS_FREE){ + if (time_after(jiffies, x)){ + DBG("%d: abort timeout, resetting...\n", dev->idx); + iic_dev_reset(dev); + return; + } + schedule(); + } + + /* Just to clear errors */ + iic_xfer_result(dev); +} + +/* + * Wait for master transfer to complete. + * It puts current process to sleep until we get interrupt or timeout expires. + * Returns the number of transferred bytes or error (<0) + */ +static int iic_wait_for_tc(struct ibm_iic_private* dev){ + + volatile struct iic_regs *iic = dev->vaddr; + int ret = 0; + + if (dev->irq >= 0){ + /* Interrupt mode */ + wait_queue_t wait; + init_waitqueue_entry(&wait, current); + + add_wait_queue(&dev->wq, &wait); + set_current_state(TASK_INTERRUPTIBLE); + if (in_8(&iic->sts) & STS_PT) + schedule_timeout(dev->adap.timeout * HZ); + set_current_state(TASK_RUNNING); + remove_wait_queue(&dev->wq, &wait); + + if (unlikely(signal_pending(current))){ + DBG("%d: wait interrupted\n", dev->idx); + ret = -ERESTARTSYS; + } else if (unlikely(in_8(&iic->sts) & STS_PT)){ + DBG("%d: wait timeout\n", dev->idx); + ret = -ETIMEDOUT; + } + } + else { + /* Polling mode */ + unsigned long x = jiffies + dev->adap.timeout * HZ; + + while (in_8(&iic->sts) & STS_PT){ + if (unlikely(time_after(jiffies, x))){ + DBG("%d: poll timeout\n", dev->idx); + ret = -ETIMEDOUT; + break; + } + + if (unlikely(signal_pending(current))){ + DBG("%d: poll interrupted\n", dev->idx); + ret = -ERESTARTSYS; + break; + } + schedule(); + } + } + + if (unlikely(ret < 0)) + iic_abort_xfer(dev); + else + ret = iic_xfer_result(dev); + + DBG2("%d: iic_wait_for_tc -> %d\n", dev->idx, ret); + + return ret; +} + +/* + * Low level master transfer routine + */ +static int iic_xfer_bytes(struct ibm_iic_private* dev, struct i2c_msg* pm, + int combined_xfer) +{ + volatile struct iic_regs *iic = dev->vaddr; + char* buf = pm->buf; + int i, j, loops, ret = 0; + int len = pm->len; + + u8 cntl = (in_8(&iic->cntl) & CNTL_AMD) | CNTL_PT; + if (pm->flags & I2C_M_RD) + cntl |= CNTL_RW; + + loops = (len + 3) / 4; + for (i = 0; i < loops; ++i, len -= 4){ + int count = len > 4 ? 4 : len; + u8 cmd = cntl | ((count - 1) << CNTL_TCT_SHIFT); + + if (!(cntl & CNTL_RW)) + for (j = 0; j < count; ++j) + out_8((volatile u8*)&iic->mdbuf, *buf++); + + if (i < loops - 1) + cmd |= CNTL_CHT; + else if (combined_xfer) + cmd |= CNTL_RPST; + + DBG2("%d: xfer_bytes, %d, CNTL = 0x%02x\n", dev->idx, count, cmd); + + /* Start transfer */ + out_8(&iic->cntl, cmd); + + /* Wait for completion */ + ret = iic_wait_for_tc(dev); + + if (unlikely(ret < 0)) + break; + else if (unlikely(ret != count)){ + DBG("%d: xfer_bytes, requested %d, transfered %d\n", + dev->idx, count, ret); + + /* If it's not a last part of xfer, abort it */ + if (combined_xfer || (i < loops - 1)) + iic_abort_xfer(dev); + + ret = -EREMOTEIO; + break; + } + + if (cntl & CNTL_RW) + for (j = 0; j < count; ++j) + *buf++ = in_8((volatile u8*)&iic->mdbuf); + } + + return ret > 0 ? 0 : ret; +} + +/* + * Set target slave address for master transfer + */ +static inline void iic_address(struct ibm_iic_private* dev, struct i2c_msg* msg) +{ + volatile struct iic_regs *iic = dev->vaddr; + u16 addr = msg->addr; + + DBG2("%d: iic_address, 0x%03x (%d-bit)\n", dev->idx, + addr, msg->flags & I2C_M_TEN ? 10 : 7); + + if (msg->flags & I2C_M_TEN){ + out_8(&iic->cntl, CNTL_AMD); + out_8(&iic->lmadr, addr); + out_8(&iic->hmadr, 0xf0 | ((addr >> 7) & 0x06)); + } + else { + out_8(&iic->cntl, 0); + out_8(&iic->lmadr, addr << 1); + } +} + +static inline int iic_invalid_address(const struct i2c_msg* p) +{ + return (p->addr > 0x3ff) || (!(p->flags & I2C_M_TEN) && (p->addr > 0x7f)); +} + +static inline int iic_address_neq(const struct i2c_msg* p1, + const struct i2c_msg* p2) +{ + return (p1->addr != p2->addr) + || ((p1->flags & I2C_M_TEN) != (p2->flags & I2C_M_TEN)); +} + +/* + * Generic master transfer entrypoint. + * Returns the number of processed messages or error (<0) + */ +static int iic_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) +{ + struct ibm_iic_private* dev = (struct ibm_iic_private*)(adap->data); + volatile struct iic_regs *iic = dev->vaddr; + int i, ret = 0; + + DBG2("%d: iic_xfer, %d msg(s)\n", dev->idx, num); + + if (!num) + return 0; + + /* Check the sanity of the passed messages. + * Uhh, generic i2c layer is more suitable place for such code... + */ + if (unlikely(iic_invalid_address(&msgs[0]))){ + DBG("%d: invalid address 0x%03x (%d-bit)\n", dev->idx, + msgs[0].addr, msgs[0].flags & I2C_M_TEN ? 10 : 7); + return -EINVAL; + } + for (i = 0; i < num; ++i){ + if (unlikely(msgs[i].len <= 0)){ + DBG("%d: invalid len %d in msg[%d]\n", dev->idx, + msgs[i].len, i); + return -EINVAL; + } + if (unlikely(iic_address_neq(&msgs[0], &msgs[i]))){ + DBG("%d: invalid addr in msg[%d]\n", dev->idx, i); + return -EINVAL; + } + } + + /* Check bus state */ + if (unlikely((in_8(&iic->extsts) & EXTSTS_BCS_MASK) != EXTSTS_BCS_FREE)){ + DBG("%d: iic_xfer, bus is not free\n", dev->idx); + + /* Usually it means something serious has happend. + * We *cannot* have unfinished previous transfer + * so it doesn't make any sense to try to stop it. + * Probably we were not able to recover from the + * previous error. + * The only *reasonable* thing I can think of here + * is soft reset. --ebs + */ + iic_dev_reset(dev); + + if ((in_8(&iic->extsts) & EXTSTS_BCS_MASK) != EXTSTS_BCS_FREE){ + DBG("%d: iic_xfer, bus is still not free\n", dev->idx); + return -EREMOTEIO; + } + } + else { + /* Flush master data buffer (just in case) */ + out_8(&iic->mdcntl, in_8(&iic->mdcntl) | MDCNTL_FMDB); + } + + /* Load slave address */ + iic_address(dev, &msgs[0]); + + /* Do real transfer */ + for (i = 0; i < num && !ret; ++i) + ret = iic_xfer_bytes(dev, &msgs[i], i < num - 1); + + return ret < 0 ? ret : num; +} + +static u32 iic_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR; +} + +static struct i2c_algorithm iic_algo = { + .name = "IBM IIC algorithm", + .id = I2C_ALGO_OCP, + .master_xfer = iic_xfer, + .smbus_xfer = NULL, + .slave_send = NULL, + .slave_recv = NULL, + .algo_control = NULL, + .functionality = iic_func +}; + +/* + * Scan bus for valid 7-bit addresses (ie things that ACK on 1 byte read) + * We only scan range [0x08 - 0x77], all other addresses are reserved anyway + */ +static void __init iic_scan_bus(struct ibm_iic_private* dev) +{ + int found = 0; + char dummy; + struct i2c_msg msg = { + .buf = &dummy, + .len = sizeof(dummy), + .flags = I2C_M_RD + }; + + printk(KERN_INFO "ibm-iic%d: scanning bus...\n" KERN_INFO, dev->idx); + + for (msg.addr = 8; msg.addr < 0x78; ++msg.addr) + if (iic_xfer(&dev->adap, &msg, 1) == 1){ + ++found; + printk(" 0x%02x", msg.addr); + } + + printk("%sibm-iic%d: %d device(s) detected\n", + found ? "\n" KERN_INFO : "", dev->idx, found); +} + +/* + * Module reference counting + */ +static void iic_inc_use(struct i2c_adapter *adap) +{ + MOD_INC_USE_COUNT; +} + +static void iic_dec_use(struct i2c_adapter *adap) +{ + MOD_DEC_USE_COUNT; +} + +/* + * Calculates IICx_CLCKDIV value for a specific OPB clock frequency + */ +static inline u8 iic_clckdiv(unsigned int opb) +{ + /* Compatibility kludge, should go away after all cards + * are fixed to fill correct value for opbfreq. + * Previous driver version used hardcoded divider value 4, + * it corresponds to OPB frequency from the range (40, 50] MHz + */ + if (!opb){ + printk(KERN_WARNING "ibm-iic: using compatibility value for OPB freq," + " fix your board specific setup\n"); + opb = 50000000; + } + + /* Convert to MHz */ + opb /= 1000000; + + if (opb < 20 || opb > 150){ + printk(KERN_CRIT "ibm-iic: invalid OPB clock frequency %u MHz\n", + opb); + opb = opb < 20 ? 20 : 150; + } + return (u8)((opb + 9) / 10 - 1); +} + +/* + * Register single IIC interface + */ +static int iic_probe(struct ocp_device *ocp){ + + struct ibm_iic_private* dev; + struct i2c_adapter* adap; + int ret; + bd_t* bd = (bd_t*)__res; + + if (!(dev = kmalloc(sizeof(*dev), GFP_KERNEL))){ + printk(KERN_CRIT "ibm-iic: failed to allocate device data\n"); + return -ENOMEM; + } + + memset(dev, 0, sizeof(*dev)); + dev->idx = ocp->def->index; + ocp_set_drvdata(ocp, dev); + + if (!(dev->vaddr = ioremap(ocp->def->paddr, sizeof(struct iic_regs)))){ + printk(KERN_CRIT "ibm-iic%d: failed to ioremap device registers\n", + dev->idx); + ret = -ENXIO; + goto fail2; + } + + init_waitqueue_head(&dev->wq); + + dev->irq = iic_force_poll ? -1 : ocp->def->irq; + if (dev->irq >= 0){ + /* Disable interrupts until we finish intialization, + assumes level-sensitive IRQ setup... + */ + iic_interrupt_mode(dev, 0); + if (request_irq(dev->irq, iic_handler, 0, "IBM IIC", dev)){ + printk(KERN_ERR "ibm-iic%d: request_irq %d failed\n", + dev->idx, dev->irq); + /* Fallback to the polling mode */ + dev->irq = -1; + } + } + + if (dev->irq < 0) + printk(KERN_WARNING "ibm-iic%d: using polling mode\n", + dev->idx); + + /* Board specific settings */ + BUG_ON(dev->idx >= sizeof(bd->bi_iic_fast) / sizeof(bd->bi_iic_fast[0])); + dev->fast_mode = iic_force_fast ? 1 : bd->bi_iic_fast[dev->idx]; + + /* clckdiv is the same for *all* IIC interfaces, + * but I'd rather make a copy than introduce another global. --ebs + */ + dev->clckdiv = iic_clckdiv(bd->bi_opb_busfreq); + DBG("%d: clckdiv = %d\n", dev->idx, dev->clckdiv); + + /* Initialize IIC interface */ + iic_dev_init(dev); + + /* Register it with i2c layer */ + adap = &dev->adap; + strcpy(adap->name, "IBM IIC"); + adap->data = dev; + adap->id = I2C_HW_OCP | iic_algo.id; + adap->algo = &iic_algo; + adap->inc_use = iic_inc_use; + adap->dec_use = iic_dec_use; + adap->client_register = NULL; + adap->client_unregister = NULL; + adap->timeout = 1; + adap->retries = 1; + + if ((ret = i2c_add_adapter(adap)) != 0){ + printk(KERN_CRIT "ibm-iic%d: failed to register i2c adapter\n", + dev->idx); + goto fail; + } + + printk(KERN_INFO "ibm-iic%d: using %s mode\n", dev->idx, + dev->fast_mode ? "fast (400 kHz)" : "standard (100 kHz)"); + + /* Scan bus if requested by user */ + if (iic_scan) + iic_scan_bus(dev); + + return 0; + +fail: + if (dev->irq >= 0){ + iic_interrupt_mode(dev, 0); + free_irq(dev->irq, dev); + } + + iounmap((void*)dev->vaddr); +fail2: + ocp_set_drvdata(ocp, 0); + kfree(dev); + return ret; +} + +/* + * Cleanup initialized IIC interface + */ +static void iic_remove(struct ocp_device *ocp) +{ + struct ibm_iic_private* dev = (struct ibm_iic_private*)ocp_get_drvdata(ocp); + BUG_ON(dev == NULL); + if (i2c_del_adapter(&dev->adap)){ + printk(KERN_CRIT "ibm-iic%d: failed to delete i2c adapter :(\n", + dev->idx); + /* That's *very* bad, just shutdown IRQ ... */ + if (dev->irq >= 0){ + iic_interrupt_mode(dev, 0); + free_irq(dev->irq, dev); + dev->irq = -1; + } + } else { + if (dev->irq >= 0){ + iic_interrupt_mode(dev, 0); + free_irq(dev->irq, dev); + } + iounmap((void*)dev->vaddr); + kfree(dev); + } +} + +static struct ocp_device_id ibm_iic_ids[] = +{ + { .vendor = OCP_VENDOR_IBM, .function = OCP_FUNC_IIC }, + { .vendor = OCP_VENDOR_INVALID } +}; + +static struct ocp_driver ibm_iic_driver = +{ + .name = "iic", + .id_table = ibm_iic_ids, + + .probe = iic_probe, + .remove = iic_remove, +}; + +static int __init iic_init(void) +{ + printk(KERN_INFO "IBM IIC driver v" DRIVER_VERSION "\n"); + if (ocp_register_driver(&ibm_iic_driver) == 0){ + /* No devices were bound to this driver */ + ocp_unregister_driver(&ibm_iic_driver); + return -ENODEV; + } + return 0; +} + +static void __exit iic_exit(void) +{ + ocp_unregister_driver(&ibm_iic_driver); +} + +module_init(iic_init); +module_exit(iic_exit); diff -N -u2 -r i2c-orig/kernel/i2c-ibm_iic.h i2c/kernel/i2c-ibm_iic.h --- i2c-orig/kernel/i2c-ibm_iic.h 1969-12-31 17:00:00.000000000 -0700 +++ i2c/kernel/i2c-ibm_iic.h 2003-09-12 16:10:29.000000000 -0700 @@ -0,0 +1,99 @@ +/* + * drivers/i2c/i2c-ibm_iic.h + * + * Support for the IIC peripheral on IBM PPC 4xx + * + * Copyright (c) 2003 Zultys Technologies. + * Eugene Surovegin <eugene.surovegin at zultys.com> or <ebs at ebshome.net> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ +#ifndef __I2C_IBM_IIC_H_ +#define __I2C_IBM_IIC_H_ + +#include <linux/config.h> +#include <linux/i2c.h> + +struct ibm_iic_private { + struct i2c_adapter adap; + volatile struct iic_regs *vaddr; + wait_queue_head_t wq; + int idx; + int irq; + int fast_mode; + u8 clckdiv; +}; + +/* IICx_CNTL register */ +#define CNTL_HMT 0x80 +#define CNTL_AMD 0x40 +#define CNTL_TCT_MASK 0x30 +#define CNTL_TCT_SHIFT 4 +#define CNTL_RPST 0x08 +#define CNTL_CHT 0x04 +#define CNTL_RW 0x02 +#define CNTL_PT 0x01 + +/* IICx_MDCNTL register */ +#define MDCNTL_FSDB 0x80 +#define MDCNTL_FMDB 0x40 +#define MDCNTL_EGC 0x20 +#define MDCNTL_FSM 0x10 +#define MDCNTL_ESM 0x08 +#define MDCNTL_EINT 0x04 +#define MDCNTL_EUBS 0x02 +#define MDCNTL_HSCL 0x01 + +/* IICx_STS register */ +#define STS_SSS 0x80 +#define STS_SLPR 0x40 +#define STS_MDBS 0x20 +#define STS_MDBF 0x10 +#define STS_SCMP 0x08 +#define STS_ERR 0x04 +#define STS_IRQA 0x02 +#define STS_PT 0x01 + +/* IICx_EXTSTS register */ +#define EXTSTS_IRQP 0x80 +#define EXTSTS_BCS_MASK 0x70 +#define EXTSTS_BCS_FREE 0x40 +#define EXTSTS_IRQD 0x08 +#define EXTSTS_LA 0x04 +#define EXTSTS_ICT 0x02 +#define EXTSTS_XFRA 0x01 + +/* IICx_INTRMSK register */ +#define INTRMSK_EIRC 0x80 +#define INTRMSK_EIRS 0x40 +#define INTRMSK_EIWC 0x20 +#define INTRMSK_EIWS 0x10 +#define INTRMSK_EIHE 0x08 +#define INTRMSK_EIIC 0x04 +#define INTRMSK_EITA 0x02 +#define INTRMSK_EIMTC 0x01 + +/* IICx_XFRCNT register */ +#define XFRCNT_MTC_MASK 0x07 + +/* IICx_XTCNTLSS register */ +#define XTCNTLSS_SRC 0x80 +#define XTCNTLSS_SRS 0x40 +#define XTCNTLSS_SWC 0x20 +#define XTCNTLSS_SWS 0x10 +#define XTCNTLSS_SRST 0x01 + +/* IICx_DIRECTCNTL register */ +#define DIRCNTL_SDAC 0x08 +#define DIRCNTL_SCC 0x04 +#define DIRCNTL_MSDA 0x02 +#define DIRCNTL_MSC 0x01 + +/* Check if we really control the I2C bus and bus is free */ +#define DIRCTNL_FREE(v) (((v) & 0x0f) == 0x0f) + +#endif /* __I2C_IBM_IIC_H_ */ diff -N -u2 -r i2c-orig/mkpatch/Config.in i2c/mkpatch/Config.in --- i2c-orig/mkpatch/Config.in 2003-07-25 00:56:42.000000000 -0700 +++ i2c/mkpatch/Config.in 2003-09-12 16:06:33.000000000 -0700 @@ -39,8 +39,5 @@ fi if [ "$CONFIG_IBM_OCP" = "y" ]; then - dep_tristate 'IBM on-chip I2C Algorithm' CONFIG_I2C_IBM_OCP_ALGO $CONFIG_I2C - if [ "$CONFIG_I2C_IBM_OCP_ALGO" != "n" ]; then - dep_tristate ' IBM on-chip I2C Adapter' CONFIG_I2C_IBM_OCP_ADAP $CONFIG_I2C_IBM_OCP_ALGO - fi + dep_tristate 'IBM IIC I2C interface' CONFIG_I2C_IBM_IIC $CONFIG_I2C fi diff -N -u2 -r i2c-orig/mkpatch/mkpatch.pl i2c/mkpatch/mkpatch.pl --- i2c-orig/mkpatch/mkpatch.pl 2003-07-25 00:56:42.000000000 -0700 +++ i2c/mkpatch/mkpatch.pl 2003-09-12 16:09:44.000000000 -0700 @@ -292,21 +292,12 @@ The module will be called i2c-rpx.o. -IBM 405 I2C algorithm -CONFIG_I2C_IBM_OCP_ALGO - This is the algorithm that allows you to use IBM 405 I2C adapters. +IBM IIC I2C interface +CONFIG_I2C_IBM_IIC + This driver supports the IBM 4xx IIC interface. This driver is also available as a module. If you want to compile it as a module, say M here and read <file:Documentation/modules.txt>. - The module will be called i2c-algo-ibm_ocp.o. - -IBM 405 I2C interface -CONFIG_I2C_IBM_OCP_ADAP - This supports the IBM 405 I2C device. - - This driver is also available as a module. If you want to compile - it as a module, say M here and read - <file:Documentation/modules.txt>. - The module will be called i2c-adap-ibm_ocp.o. + The module will be called i2c-ibm_iic.o. StrongARM SA-1110 interface @@ -561,6 +552,5 @@ obj-$(CONFIG_I2C_ALGO8XX) += i2c-algo-8xx.o obj-$(CONFIG_I2C_RPXLITE) += i2c-rpx.o -obj-$(CONFIG_I2C_IBM_OCP_ALGO) += i2c-algo-ibm_ocp.o -obj-$(CONFIG_I2C_IBM_OCP_ADAP) += i2c-adap-ibm_ocp.o +obj-$(CONFIG_I2C_IBM_IIC) += i2c-ibm_iic.o obj-$(CONFIG_I2C_FRODO) += i2c-frodo.o