8xx: i2c-algo-8xx - fixed timeout detection and transmission errors
cajus.hahn at de.abb.com
cajus.hahn at de.abb.com
Wed Aug 10 17:27:57 EST 2005
Hi all,
I had some problems on my MPC855M based board when I tried to access the
i2c bus.
The cause were some disturbances on the i2c bus. If a slave device or
another master device hold the SDA or SCL line low, the CPM will get into a
state, where no more transmissions are made. The only way I found, to get
the CPM back to work, was a complete re-initialisation. -> force_reinit()
In this case the busy-wait for transmissions with count < 16 will lock the
complete system (CPU load 99.9%)
I added the define I2C_BUSY_WAIT to switch between faster access or safer
system.
I found out that the i2c-algo-8xx.c has a bug in cpm_iic_read() and
cpm_iic_write(): the timeout detection will not work in the case of count <
16.
I also added the define I2C_INTERRUPTIBLE_SLEEP: the old driver reported
IO-error (-EIO) if a timeout occured (which was not working, see above) or
if a signal was pending. This caused some problems if the process receives
user-signals. The driver will report IO-error, which is not correct. With
the busy-wait this effect might not be seen, because there will be no
process scheduling -> no signals might be send.
My modified file is appended. The defines for I2C_BUSY_WAIT and
I2C_INTERRUPTIBLE_SLEEP are active, which let the driver act like the old
one.
Maybe this is helpful for others too and some of the modifications find
it´s way into the official kernel tree.
Cajus Hahn
/*
* i2c-algo-8xx.c i2x driver algorithms for MPC8XX CPM
* Copyright (c) 1999 Dan Malek (dmalek at jlc.net).
*
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* moved into proper i2c interface; separated out platform specific
* parts into i2c-rpx.c
* Brad Parker (brad at heeltoe.com)
*
* added define for BUSY_WAIT and INTERRUPTIBLE_SLEEP, added
I2C_ALGO_8XX_DATE + ..VERSION
* fixed bug in cpm_iic_read and cpm_iic_write (timeout never detected if
count < 16)
* added force_reinit(): in certain cases (disturbances on the I2C bus) a
timeout will
* occur. After this a complete re-initialisation will be necessary,
otherwise all
* following transmissions will have a timeout.
* Cajus Hahn, 09.08.2005
*/
// XXX todo
// timeout sleep?
/* $Id: i2c-algo-8xx.c,v 1.1.1.1 2004/12/10 08:44:35 cajus 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 <asm/commproc.h>
#include <linux/i2c.h>
#include <linux/i2c-algo-8xx.h>
#define I2C_ALGO_8XX_DATE "20050809"
#define I2C_ALGO_8XX_VERSION "2.6.2"
#define CPM_MAX_READ 513
/* #define I2C_CHIP_ERRATA */ /* Try uncomment this if you have an older
CPU(earlier than rev D4) */
#define I2C_BUSY_WAIT /* Uncomment this if you want to do a busy wait in
cpm_iic_read and cpm_iic_write */
#define I2C_INTERRUPTIBLE_SLEEP /* Uncomment this if you want the waiting
in cpm_iic_read and
cpm_iic_write beeing interruptable
by signals */
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, struct pt_regs *regs)
{
volatile i2c8xx_t *i2c = (i2c8xx_t *)dev_id;
if (cpm_debug > 1)
printk(KERN_DEBUG "cpm_iic_interrupt(dev_id=%p)\n", dev_id);
#ifdef I2C_CHIP_ERRATA
/* Chip errata, clear enable.
* This seems to not be needed on rev D4 or newer CPUs.
* Someone with an older CPU needs to verify this.
*/
i2c->i2c_i2mod &= ~1;
#endif
/* Clear interrupt.
*/
i2c->i2c_i2cer = 0xff;
/* Get 'me going again.
*/
#ifdef I2C_INTERRUPTIBLE_SLEEP
wake_up_interruptible(&iic_wait);
#else
wake_up(&iic_wait);
#endif
}
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;
unsigned char brg;
bd_t *bd = (bd_t *)__res;
if (cpm_debug) printk(KERN_DEBUG "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);
} else {
iip->iic_rbptr = iip->iic_rbase;
iip->iic_tbptr = iip->iic_tbase;
iip->iic_rstate = 0;
iip->iic_tstate = 0;
}
/* Select an arbitrary address. Just make sure it is unique.
*/
i2c->i2c_i2add = 0xfe;
/* Make clock run at 60 KHz.
*/
brg = (unsigned char) (bd->bi_intfreq/(32*2*60000) -3);
i2c->i2c_i2brg = brg;
i2c->i2c_i2mod = 0x00;
i2c->i2c_i2com = 0x01; /* Master mode */
/* Disable interrupts.
*/
i2c->i2c_i2cmr = 0;
i2c->i2c_i2cer = 0xff;
init_waitqueue_head(&iic_wait);
/* Install interrupt handler.
*/
if (cpm_debug) {
printk (KERN_DEBUG "%s[%d] Install ISR for IRQ %d\n",
__func__,__LINE__, CPMVEC_I2C);
}
cpm_install_handler(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 &= ~1;
i2c->i2c_i2cmr = 0;
i2c->i2c_i2cer = 0xff;
return(0);
}
static void
cpm_reset_iic_params(volatile iic_t *iip)
{
iip->iic_tbase = r_tbase;
iip->iic_rbase = r_rbase;
iip->iic_tfcr = SMC_EB;
iip->iic_rfcr = SMC_EB;
iip->iic_mrblr = CPM_MAX_READ;
iip->iic_rstate = 0;
iip->iic_rdp = 0;
iip->iic_rbptr = iip->iic_rbase;
iip->iic_rbc = 0;
iip->iic_rxtmp = 0;
iip->iic_tstate = 0;
iip->iic_tdp = 0;
iip->iic_tbptr = iip->iic_tbase;
iip->iic_tbc = 0;
iip->iic_txtmp = 0;
}
#define BD_SC_NAK ((ushort)0x0004) /* NAK - did not respond */
#define BD_SC_OV ((ushort)0x0002) /* OV - receive overrun */
#define CPM_CR_CLOSE_RXBD ((ushort)0x0007)
static void force_close(struct i2c_algo_8xx_data *cpm)
{
volatile i2c8xx_t *i2c = cpm->i2c;
if (cpm_debug)
printk(KERN_DEBUG "force_close()");
if (cpm->reloc == 0) { /* micro code disabled */
volatile cpm8xx_t *cp = cpm->cp;
cp->cp_cpcr =
mk_cr_cmd(CPM_CR_CH_I2C, CPM_CR_CLOSE_RXBD) |
CPM_CR_FLG;
while (cp->cp_cpcr & CPM_CR_FLG);
}
i2c->i2c_i2cmr = 0x00; /* Disable all interrupts */
i2c->i2c_i2cer = 0xff;
}
static void force_reinit(struct i2c_algo_8xx_data *cpm)
{
volatile iic_t *iip = cpm->iip;
volatile i2c8xx_t *i2c = cpm->i2c;
volatile cpm8xx_t *cp = cpm->cp;
unsigned char brg;
bd_t *bd = (bd_t *)__res;
// Disable interrupts.
i2c->i2c_i2cmr = 0;
i2c->i2c_i2cer = 0xff;
// Clear enable
i2c->i2c_i2mod &= ~1;
// Initialize the parameter ram.
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;
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;
if (cpm->reloc == 0)
{
cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_I2C, CPM_CR_INIT_TRX) |
CPM_CR_FLG;
while (cp->cp_cpcr & CPM_CR_FLG);
}
else
{
iip->iic_rbptr = iip->iic_rbase;
iip->iic_tbptr = iip->iic_tbase;
iip->iic_rstate = 0;
iip->iic_tstate = 0;
}
// Select an arbitrary address. Just make sure it is unique.
i2c->i2c_i2add = 0xfe;
// Make clock run at 60 KHz.
brg = (unsigned char) (bd->bi_intfreq/(32*2*60000) -3);
i2c->i2c_i2brg = brg;
i2c->i2c_i2mod = 0x00;
i2c->i2c_i2com = 0x01; /* Master mode */
}
/* Read from IIC...
* abyte = address byte, with r/w flag already set
*/
static int
cpm_iic_read(struct i2c_algo_8xx_data *cpm, u_char abyte, char *buf, int
count)
{
volatile iic_t *iip = cpm->iip;
volatile i2c8xx_t *i2c = cpm->i2c;
volatile cpm8xx_t *cp = cpm->cp;
volatile cbd_t *tbdf, *rbdf;
u_char *tb;
unsigned long flags, tmo, timedout;
if (count >= CPM_MAX_READ)
return -EINVAL;
/* check for and use a microcode relocation patch */
if (cpm->reloc) {
cpm_reset_iic_params(iip);
}
tbdf = (cbd_t *)&cp->cp_dpmem[iip->iic_tbase];
rbdf = (cbd_t *)&cp->cp_dpmem[iip->iic_rbase];
/* To read, we need an empty buffer of the proper length.
* All that is used is the first byte for address, the remainder
* is just used for timing (and doesn't really have to exist).
*/
tb = cpm->temp;
tb = (u_char *)(((uint)tb + 15) & ~15);
tb[0] = abyte; /* Device address byte w/rw flag */
flush_dcache_range((unsigned long) tb, (unsigned long) (tb+1));
if (cpm_debug) printk(KERN_DEBUG "cpm_iic_read(abyte=0x%x)\n",
abyte);
tbdf->cbd_bufaddr = __pa(tb);
tbdf->cbd_datlen = count + 1;
tbdf->cbd_sc =
BD_SC_READY | BD_SC_LAST |
BD_SC_WRAP | BD_IIC_START;
iip->iic_mrblr = count + 1; /* prevent excessive read, +1
is needed otherwise will the
RXB interrupt come too early */
/* flush will invalidate too. */
flush_dcache_range((unsigned long) buf, (unsigned long) (buf+count));
rbdf->cbd_datlen = 0;
rbdf->cbd_bufaddr = __pa(buf);
rbdf->cbd_sc = BD_SC_EMPTY | BD_SC_WRAP| BD_SC_INTRPT;
timedout = 0;
#ifdef I2C_BUSY_WAIT
if(count > 16){
#endif
/* Chip bug, set enable here */
local_irq_save(flags);
i2c->i2c_i2cmr = 0x13; /* Enable some interupts */
i2c->i2c_i2cer = 0xff;
i2c->i2c_i2mod |= 1; /* Enable */
i2c->i2c_i2com |= 0x80; /* Begin transmission */
/* Wait for IIC transfer */
#ifdef I2C_INTERRUPTIBLE_SLEEP
tmo = interruptible_sleep_on_timeout(&iic_wait,1*HZ);
#else
tmo = sleep_on_timeout(&iic_wait,1*HZ);
#endif
if(tmo == 0) timedout=1;
local_irq_restore(flags);
#ifdef I2C_BUSY_WAIT
} else { /* busy wait for small transfers, its faster */
i2c->i2c_i2cmr = 0x00; /* Disable I2C interupts */
i2c->i2c_i2cer = 0xff;
i2c->i2c_i2mod |= 1; /* Enable */
i2c->i2c_i2com |= 0x80; /* Begin transmission */
tmo = jiffies + 1*HZ;
while(!(i2c->i2c_i2cer & 0x11 || (timedout =
time_after(jiffies, tmo)))); /* Busy wait, with a timeout */
}
#endif
if(timedout)
{
printk(KERN_DEBUG "cpm_iic_read: timeout!\n");
force_reinit(cpm);
return -EIO;
}
#ifdef I2C_INTERRUPTIBLE_SLEEP
if (signal_pending(current))
{
force_close(cpm);
if (cpm_debug)
printk(KERN_DEBUG "cpm_iic_read: signal_pending! \n");
return -EINTR;
}
#endif
#ifdef I2C_CHIP_ERRATA
/* Chip errata, clear enable. This is not needed on rev D4 CPUs.
Disabling I2C too early may cause too short stop condition */
udelay(4);
i2c->i2c_i2mod &= ~1;
#endif
if (cpm_debug) {
printk(KERN_DEBUG "tx sc %04x, rx sc %04x\n",
tbdf->cbd_sc, rbdf->cbd_sc);
}
if (tbdf->cbd_sc & BD_SC_READY) {
printk(KERN_INFO "IIC read; complete but tbuf ready\n");
force_close(cpm);
printk(KERN_INFO "tx sc %04x, rx sc %04x\n",
tbdf->cbd_sc, rbdf->cbd_sc);
}
if (tbdf->cbd_sc & BD_SC_NAK) {
if (cpm_debug)
printk(KERN_DEBUG "IIC read; no ack\n");
return -EREMOTEIO;
}
if (rbdf->cbd_sc & BD_SC_EMPTY) {
/* force_close(cpm); */
if (cpm_debug){
printk(KERN_DEBUG "IIC read; complete but rbuf empty\n");
printk(KERN_DEBUG "tx sc %04x, rx sc %04x\n",
tbdf->cbd_sc, rbdf->cbd_sc);
}
return -EREMOTEIO;
}
if (rbdf->cbd_sc & BD_SC_OV) {
if (cpm_debug)
printk(KERN_DEBUG "IIC read; Overrun\n");
return -EREMOTEIO;;
}
if (cpm_debug) printk(KERN_DEBUG "read %d bytes\n",
rbdf->cbd_datlen);
if (rbdf->cbd_datlen < count) {
if (cpm_debug)
printk(KERN_DEBUG "IIC read; short, wanted %d got %d\n",
count, rbdf->cbd_datlen);
return 0;
}
return count;
}
/* Write to IIC...
* addr = address byte, with r/w flag already set
*/
static int
cpm_iic_write(struct i2c_algo_8xx_data *cpm, u_char abyte, char *buf,int
count)
{
volatile iic_t *iip = cpm->iip;
volatile i2c8xx_t *i2c = cpm->i2c;
volatile cpm8xx_t *cp = cpm->cp;
volatile cbd_t *tbdf;
u_char *tb;
unsigned long flags, tmo, timedout;
/* check for and use a microcode relocation patch */
if (cpm->reloc) {
cpm_reset_iic_params(iip);
}
tb = cpm->temp;
tb = (u_char *)(((uint)tb + 15) & ~15);
*tb = abyte; /* Device address byte w/rw flag */
flush_dcache_range((unsigned long) tb, (unsigned long) (tb+1));
flush_dcache_range((unsigned long) buf, (unsigned long) (buf+count));
if (cpm_debug) printk(KERN_DEBUG "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;
timedout = 0;
#ifdef I2C_BUSY_WAIT
if(count > 16){
#endif
/* Chip bug, set enable here */
local_irq_save(flags);
i2c->i2c_i2cmr = 0x13; /* Enable some interupts */
i2c->i2c_i2cer = 0xff;
i2c->i2c_i2mod |= 1; /* Enable */
i2c->i2c_i2com |= 0x80; /* Begin transmission */
/* Wait for IIC transfer */
#ifdef I2C_INTERRUPTIBLE_SLEEP
tmo = interruptible_sleep_on_timeout(&iic_wait,1*HZ);
#else
tmo = sleep_on_timeout(&iic_wait,1*HZ);
#endif
if(tmo == 0) timedout=1;
local_irq_restore(flags);
#ifdef I2C_BUSY_WAIT
} else { /* busy wait for small transfers, its faster */
i2c->i2c_i2cmr = 0x00; /* Disable I2C interupts */
i2c->i2c_i2cer = 0xff;
i2c->i2c_i2mod |= 1; /* Enable */
i2c->i2c_i2com |= 0x80; /* Begin transmission */
tmo = jiffies + 1*HZ;
while(!(i2c->i2c_i2cer & 0x12 || (timedout =
time_after(jiffies, tmo)))); /* Busy wait, with a timeout */
}
#endif
if(timedout)
{
printk(KERN_DEBUG "cpm_iic_write: timeout!\n");
force_reinit(cpm);
return -EIO;
}
#ifdef I2C_INTERRUPTIBLE_SLEEP
if (signal_pending(current))
{
force_close(cpm);
if (cpm_debug)
printk(KERN_DEBUG "cpm_iic_write: signal_pending! \n");
return -EINTR;
}
#endif
#if I2C_CHIP_ERRATA
/* Chip errata, clear enable. This is not needed on rev D4 CPUs.
Disabling I2C too early may cause too short stop condition */
udelay(4);
i2c->i2c_i2mod &= ~1;
#endif
if (cpm_debug) {
printk(KERN_DEBUG "tx0 sc %04x, tx1 sc %04x\n",
tbdf[0].cbd_sc, tbdf[1].cbd_sc);
}
if ((tbdf[0].cbd_sc | tbdf[1].cbd_sc) & BD_SC_NAK) {
if (cpm_debug)
printk(KERN_DEBUG "IIC write; no ack\n");
return 0;
}
if ((tbdf[0].cbd_sc | tbdf[1].cbd_sc) & BD_SC_READY) {
if (cpm_debug)
printk(KERN_DEBUG "IIC write; complete but tbuf
ready\n");
return 0;
}
return count;
}
/* See if an IIC address exists..
* addr = 7 bit address, unshifted
*/
static int
cpm_iic_tryaddress(struct i2c_algo_8xx_data *cpm, int addr)
{
volatile iic_t *iip = cpm->iip;
volatile i2c8xx_t *i2c = cpm->i2c;
volatile cpm8xx_t *cp = cpm->cp;
volatile cbd_t *tbdf, *rbdf;
u_char *tb;
unsigned long flags, len, tmo;
if (cpm_debug > 1)
printk(KERN_DEBUG "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(KERN_DEBUG "iip %p, dp_addr 0x%x\n", cpm->iip,
cpm->dp_addr);
printk(KERN_DEBUG "iic_tbase %d, r_tbase %d\n", iip->iic_tbase,
r_tbase);
}
tbdf = (cbd_t *)&cp->cp_dpmem[iip->iic_tbase];
rbdf = (cbd_t *)&cp->cp_dpmem[iip->iic_rbase];
tb = cpm->temp;
tb = (u_char *)(((uint)tb + 15) & ~15);
/* do a simple read */
tb[0] = (addr << 1) | 1; /* device address (+ read) */
len = 2;
flush_dcache_range((unsigned long) tb, (unsigned long) (tb+1));
tbdf->cbd_bufaddr = __pa(tb);
tbdf->cbd_datlen = len;
tbdf->cbd_sc =
BD_SC_READY | BD_SC_LAST |
BD_SC_WRAP | BD_IIC_START;
rbdf->cbd_datlen = 0;
rbdf->cbd_bufaddr = __pa(tb+2);
rbdf->cbd_sc = BD_SC_EMPTY | BD_SC_WRAP | BD_SC_INTRPT;
local_irq_save(flags);
i2c->i2c_i2cmr = 0x13; /* Enable some interupts */
i2c->i2c_i2cer = 0xff;
i2c->i2c_i2mod |= 1; /* Enable */
i2c->i2c_i2com |= 0x80; /* Begin transmission */
if (cpm_debug > 1) printk(KERN_DEBUG "about to sleep\n");
/* wait for IIC transfer */
#ifdef I2C_INTERRUPTIBLE_SLEEP
tmo = interruptible_sleep_on_timeout(&iic_wait,1*HZ);
#else
tmo = sleep_on_timeout(&iic_wait,1*HZ);
#endif
local_irq_restore(flags);
#ifdef I2C_CHIP_ERRATA
/* Chip errata, clear enable. This is not needed on rev D4 CPUs.
Disabling I2C too early may cause too short stop condition */
udelay(4);
i2c->i2c_i2mod &= ~1;
#endif
if (signal_pending(current) || !tmo){
force_close(cpm);
if(cpm_debug && !tmo)
printk(KERN_DEBUG "IIC tryaddress: timeout!\n");
return -EIO;
}
if (cpm_debug > 1) printk(KERN_DEBUG "back from sleep\n");
if (tbdf->cbd_sc & BD_SC_NAK) {
if (cpm_debug > 1) printk(KERN_DEBUG "IIC try; no ack\n");
return 0;
}
if (tbdf->cbd_sc & BD_SC_READY) {
printk(KERN_INFO "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(KERN_DEBUG "i2c-algo-8xx.o: "
"#%d addr=0x%x flags=0x%x len=%d\n buf=%lx\n",
i, pmsg->addr, pmsg->flags, pmsg->len, (unsigned
long)pmsg->buf);
addr = pmsg->addr << 1;
if (pmsg->flags & I2C_M_RD )
addr |= 1;
if (pmsg->flags & I2C_M_REV_DIR_ADDR )
addr ^= 1;
if (!(pmsg->flags & I2C_M_NOSTART)) {
}
if (pmsg->flags & I2C_M_RD ) {
/* read bytes into buffer*/
ret = cpm_iic_read(adap, addr, pmsg->buf, pmsg->len);
if (cpm_debug)
printk(KERN_DEBUG "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(KERN_DEBUG "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(KERN_DEBUG "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(KERN_INFO "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(KERN_INFO "i2c-algo-8xx.o: i2c mpc8xx algorithm module version
%s (%s)\n", I2C_ALGO_8XX_VERSION, I2C_ALGO_8XX_DATE);
return 0;
}
#ifdef MODULE
MODULE_AUTHOR("Brad Parker <brad at heeltoe.com>");
MODULE_DESCRIPTION("I2C-Bus MPC8XX algorithm");
#ifdef MODULE_LICENSE
MODULE_LICENSE("GPL");
#endif
int init_module(void)
{
return i2c_algo_8xx_init();
}
void cleanup_module(void)
{
}
#endif
More information about the Linuxppc-embedded
mailing list