Volunteers to test i2c-algo-8xx on v2.6?

Marcelo Tosatti marcelo.tosatti at cyclades.com
Sun Aug 7 10:34:52 EST 2005


On Sat, Aug 06, 2005 at 09:08:15PM -0300, Aristeu Sergio Rozanski Filho wrote:
> > Would be good to test before submitting? :)
> I would like but I don't have the hardware and Alex (who reported this
> on bugzilla) told me he doesn't have it anymore. feel free to discard it
> until someone tests it

Does anyone volunteer to test this 8xx i2c driver?

> 
> > > +static  void
> > > +cpm_iic_interrupt(void *dev_id, struct pt_regs *regs)
> > > + {
> > > +	volatile i2c8xx_t *i2c = (i2c8xx_t *)dev_id;
> > 
> > You got an extra space everywhere other than the initial TAB?
> fixed this and others I found in the file, patch attached
> 
> -- 
> Aristeu
> 

> 8xx: port i2c-algo_8xx to 2.6
> 
> Based on Tom Rini's work
> 
> Signed-off-by: Aristeu Sergio Rozanski Filho <aris at cathedrallabs.org>
> 
> Index: 8xx/drivers/i2c/algos/i2c-algo-8xx.c
> ===================================================================
> --- /dev/null	1970-01-01 00:00:00.000000000 +0000
> +++ 8xx/drivers/i2c/algos/i2c-algo-8xx.c	2005-08-06 21:04:37.000000000 -0300
> @@ -0,0 +1,625 @@
> +/*
> + * 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)
> + */
> +
> +// XXX todo
> +// timeout sleep?
> +
> +/* $Id: i2c-algo-8xx.c,v 1.7 2002/08/03 22:48:18 ac9410 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 CPM_MAX_READ	513
> +/* Try uncomment this if you have an older CPU(earlier than rev D4) */
> +/* #define I2C_CHIP_ERRATA */
> +
> +static char *module_name = "i2c_algo_8xx";
> +#define DEBUGP(level, x, y...) do { \
> +				if (cpm_debug >= level) \
> +					printk(KERN_DEBUG "%s: " x, \
> +					       module_name, ## y); \
> +				} while(0)
> +
> +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;
> +
> +	DEBUGP(2, "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.
> +	*/
> +	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;
> +	unsigned char brg;
> +	bd_t *bd = (bd_t *)__res;
> +
> +	DEBUGP(1, "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.
> +	*/
> +	DEBUGP(1, "Install ISR for IRQ %d\n", 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->reloc == 0) { /* micro code disabled */
> +		volatile cpm8xx_t *cp = cpm->cp;
> +
> +		DEBUGP(1, "force_close()\n");
> +		cp->cp_cpcr =
> +			mk_cr_cmd(CPM_CR_CH_I2C, CPM_CR_CLOSE_RXBD) |
> +			CPM_CR_FLG;
> +
> +		while (cp->cp_cpcr & CPM_CR_FLG);
> +	}
> +	i2c->i2c_i2cmr = 0x00;	/* Disable all interrupts */
> +	i2c->i2c_i2cer = 0xff;
> +}
> +
> +
> +/* Read from IIC...
> + * abyte = address byte, with r/w flag already set
> + */
> +static int
> +cpm_iic_read(struct i2c_algo_8xx_data *cpm, u_char abyte, char *buf, int count)
> +{
> +	volatile iic_t *iip = cpm->iip;
> +	volatile i2c8xx_t *i2c = cpm->i2c;
> +	volatile cpm8xx_t *cp = cpm->cp;
> +	volatile cbd_t	*tbdf, *rbdf;
> +	u_char *tb;
> +	unsigned long flags, tmo;
> +
> +	if (count >= CPM_MAX_READ)
> +		return -EINVAL;
> +
> +	/* check for and use a microcode relocation patch */
> +	if (cpm->reloc)
> +		cpm_reset_iic_params(iip);
> +
> +	tbdf = (cbd_t *)&cp->cp_dpmem[iip->iic_tbase];
> +	rbdf = (cbd_t *)&cp->cp_dpmem[iip->iic_rbase];
> +
> +	/* To read, we need an empty buffer of the proper length.
> +	 * All that is used is the first byte for address, the remainder
> +	 * is just used for timing (and doesn't really have to exist).
> +	 */
> +	tb = cpm->temp;
> +	tb = (u_char *)(((uint)tb + 15) & ~15);
> +	tb[0] = abyte;		/* Device address byte w/rw flag */
> +
> +	flush_dcache_range((unsigned long) tb, (unsigned long) (tb + 1));
> +
> +	DEBUGP(1, "cpm_iic_read(abyte=0x%x)\n", abyte);
> +
> +	tbdf->cbd_bufaddr = __pa(tb);
> +	tbdf->cbd_datlen = count + 1;
> +	tbdf->cbd_sc =
> +		BD_SC_READY | BD_SC_LAST |
> +		BD_SC_WRAP | BD_IIC_START;
> +
> +	iip->iic_mrblr = count + 1; /* prevent excessive read, +1
> +				      is needed otherwise will the
> +				      RXB interrupt come too early */
> +
> +	/* flush will invalidate too. */
> +	flush_dcache_range((unsigned long) buf, (unsigned long) (buf+count));
> +
> +	rbdf->cbd_datlen = 0;
> +	rbdf->cbd_bufaddr = __pa(buf);
> +
> +	rbdf->cbd_sc = BD_SC_EMPTY | BD_SC_WRAP| BD_SC_INTRPT;
> +	if(count > 16){
> +		/* Chip bug, set enable here */
> +		local_irq_save(flags);
> +		i2c->i2c_i2cmr = 0x13;	/* Enable some interupts */
> +		i2c->i2c_i2cer = 0xff;
> +		i2c->i2c_i2mod |= 1;	/* Enable */
> +		i2c->i2c_i2com |= 0x80;	/* Begin transmission */
> +
> +		/* Wait for IIC transfer */
> +		tmo = interruptible_sleep_on_timeout(&iic_wait,1*HZ);
> +		local_irq_restore(flags);
> +	} else { /* busy wait for small transfers, its faster */
> +		i2c->i2c_i2cmr = 0x00;	/* Disable I2C interupts */
> +		i2c->i2c_i2cer = 0xff;
> +		i2c->i2c_i2mod |= 1;	/* Enable */
> +		i2c->i2c_i2com |= 0x80;	/* Begin transmission */
> +		tmo = jiffies + 1*HZ;
> +	       	/* Busy wait, with a timeout */
> +		while(!(i2c->i2c_i2cer & 0x11 || time_after(jiffies, tmo)));
> +	}
> +
> +	if (signal_pending(current) || !tmo){
> +		force_close(cpm);
> +		DEBUGP(1, "IIC read: timeout!\n");
> +		return -EIO;
> +	}
> +#ifdef I2C_CHIP_ERRATA
> +	/* Chip errata, clear enable. This is not needed on rev D4 CPUs.
> +	 Disabling I2C too early may cause too short stop condition */
> +	udelay(4);
> +	i2c->i2c_i2mod &= ~1;
> +#endif
> +
> +	DEBUGP(1, "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) {
> +		DEBUGP(1, "IIC read; no ack\n");
> +		return -EREMOTEIO;
> +	}
> +
> +	if (rbdf->cbd_sc & BD_SC_EMPTY) {
> +		/* force_close(cpm); */
> +		DEBUGP(1, "IIC read; complete but rbuf empty\n");
> +		DEBUGP(1, "tx sc %04x, rx sc %04x\n", tbdf->cbd_sc, rbdf->cbd_sc);
> +		return -EREMOTEIO;
> +	}
> +
> +	if (rbdf->cbd_sc & BD_SC_OV) {
> +		DEBUGP(1, "IIC read; Overrun\n");
> +		return -EREMOTEIO;;
> +	}
> +
> +	DEBUGP(1, "read %d bytes\n", rbdf->cbd_datlen);
> +
> +	if (rbdf->cbd_datlen < count) {
> +		DEBUGP(1, "IIC read; short, wanted %d got %d\n", count,
> +		       rbdf->cbd_datlen);
> +		return 0;
> +	}
> +
> +	return count;
> +}
> +
> +/* Write to IIC...
> + * addr = address byte, with r/w flag already set
> + */
> +static int
> +cpm_iic_write(struct i2c_algo_8xx_data *cpm, u_char abyte, char *buf,int count)
> +{
> +	volatile iic_t *iip = cpm->iip;
> +	volatile i2c8xx_t *i2c = cpm->i2c;
> +	volatile cpm8xx_t *cp = cpm->cp;
> +	volatile cbd_t	*tbdf;
> +	u_char *tb;
> +	unsigned long flags, tmo;
> +
> +	/* check for and use a microcode relocation patch */
> +	if (cpm->reloc)
> +		cpm_reset_iic_params(iip);
> +	tb = cpm->temp;
> +	tb = (u_char *)(((uint)tb + 15) & ~15);
> +	*tb = abyte;		/* Device address byte w/rw flag */
> +
> +	flush_dcache_range((unsigned long) tb, (unsigned long) (tb+1));
> +	flush_dcache_range((unsigned long) buf, (unsigned long) (buf+count));
> +
> +	DEBUGP(1, "cpm_iic_write(abyte=0x%x)\n", abyte);
> +
> +	/* set up 2 descriptors */
> +	tbdf = (cbd_t *)&cp->cp_dpmem[iip->iic_tbase];
> +
> +	tbdf[0].cbd_bufaddr = __pa(tb);
> +	tbdf[0].cbd_datlen = 1;
> +	tbdf[0].cbd_sc = BD_SC_READY | BD_IIC_START;
> +
> +	tbdf[1].cbd_bufaddr = __pa(buf);
> +	tbdf[1].cbd_datlen = count;
> +	tbdf[1].cbd_sc = BD_SC_READY | BD_SC_INTRPT | BD_SC_LAST | BD_SC_WRAP;
> +
> +	if (count > 16) {
> +		/* Chip bug, set enable here */
> +		local_irq_save(flags);
> +		i2c->i2c_i2cmr = 0x13;	/* Enable some interupts */
> +		i2c->i2c_i2cer = 0xff;
> +		i2c->i2c_i2mod |= 1;	/* Enable */
> +		i2c->i2c_i2com |= 0x80;	/* Begin transmission */
> +
> +		/* Wait for IIC transfer */
> +		tmo = interruptible_sleep_on_timeout(&iic_wait,1*HZ);
> +		local_irq_restore(flags);
> +	} else {  /* busy wait for small transfers, its faster */
> +		i2c->i2c_i2cmr = 0x00;	/* Disable I2C interupts */
> +		i2c->i2c_i2cer = 0xff;
> +		i2c->i2c_i2mod |= 1;	/* Enable */
> +		i2c->i2c_i2com |= 0x80;	/* Begin transmission */
> +		tmo = jiffies + 1*HZ;
> +	       	/* Busy wait, with a timeout */
> +		while(!(i2c->i2c_i2cer & 0x12 || time_after(jiffies, tmo)));
> +	}
> +
> +	if (signal_pending(current) || !tmo){
> +		force_close(cpm);
> +		if (!tmo)
> +			DEBUGP(1, "IIC write: timeout!\n");
> +		return -EIO;
> +	}
> +
> +#if I2C_CHIP_ERRATA
> +	/* Chip errata, clear enable. This is not needed on rev D4 CPUs.
> +	 Disabling I2C too early may cause too short stop condition */
> +	udelay(4);
> +	i2c->i2c_i2mod &= ~1;
> +#endif
> +	DEBUGP(1, "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) {
> +		DEBUGP(1, "IIC write; no ack\n");
> +		return 0;
> +	}
> +
> +	if ((tbdf[0].cbd_sc | tbdf[1].cbd_sc) & BD_SC_READY) {
> +		DEBUGP(1, "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;
> +
> +	DEBUGP(2, "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 (addr == 0) {
> +		DEBUGP(1, "iip %p, dp_addr 0x%x\n", cpm->iip, cpm->dp_addr);
> +		DEBUGP(1, "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 */
> +
> +	DEBUGP(1, "about to sleep\n");
> +
> +	/* wait for IIC transfer */
> +	tmo = interruptible_sleep_on_timeout(&iic_wait,1*HZ);
> +	local_irq_restore(flags);
> +
> +#ifdef I2C_CHIP_ERRATA
> +	/* Chip errata, clear enable. This is not needed on rev D4 CPUs.
> +	 Disabling I2C too early may cause too short stop condition */
> +	udelay(4);
> +	i2c->i2c_i2mod &= ~1;
> +#endif
> +
> +	if (signal_pending(current) || !tmo){
> +		force_close(cpm);
> +		if (!tmo)
> +			DEBUGP(1, "IIC tryaddress: timeout!\n");
> +		return -EIO;
> +	}
> +
> +	DEBUGP(2, "back from sleep\n");
> +
> +	if (tbdf->cbd_sc & BD_SC_NAK) {
> +		DEBUGP(2, "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];
> +
> +		DEBUGP(1, "#%d addr=0x%x flags=0x%x len=%d\n buf=%p\n",
> +		       i, pmsg->addr, pmsg->flags, pmsg->len, 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_RD) {
> +			/* read bytes into buffer*/
> +			ret = cpm_iic_read(adap, addr, pmsg->buf, pmsg->len);
> +			DEBUGP(1, "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);
> +			DEBUGP(1, "wrote %d\n", ret);
> +			if (ret < pmsg->len)
> +				return (ret < 0)? ret:-EREMOTEIO;
> +		}
> +	}
> +	return num;
> +}
> +
> +static u32 cpm_func(struct i2c_adapter *adap)
> +{
> +	return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR |
> +	       I2C_FUNC_PROTOCOL_MANGLING;
> +}
> +
> +static struct i2c_algorithm i2c_algo_8xx = {
> +	.name = "MPC8xx CPM algorithm",
> +	.id = I2C_ALGO_MPC8XX,
> +	.master_xfer = cpm_xfer,
> +	.functionality = cpm_func,
> +};
> +
> +/*
> + * registering functions to load algorithms at runtime
> + */
> +int i2c_8xx_add_bus(struct i2c_adapter *adap)
> +{
> +	int i;
> +	struct i2c_algo_8xx_data *cpm_adap = adap->algo_data;
> +
> +	DEBUGP(1, "hw routines for %s registered.\n", adap->name);
> +
> +	/* register new adapter to i2c module... */
> +
> +	adap->id |= i2c_algo_8xx.id;
> +	adap->algo = &i2c_algo_8xx;
> +
> +	i2c_add_adapter(adap);
> +	cpm_iic_init(cpm_adap);
> +
> +	/* scan bus */
> +	if (cpm_scan) {
> +		printk(KERN_INFO "%s: scanning bus %s...\n", module_name,
> +		       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 "%s: adapter unregistered: %s\n", module_name,
> +	       adap->name);
> +
> +	return 0;
> +}
> +
> +module_param(cpm_debug, int, S_IRUGO | S_IWUSR);
> +MODULE_PARM_DESC(cpm_debug, "Sets the debug level. (0 = none, 1 = normal, "
> +		 ">1 = plenty");
> +MODULE_AUTHOR("Brad Parker <brad at heeltoe.com>");
> +MODULE_DESCRIPTION("I2C-Bus MPC8XX algorithm");
> +MODULE_LICENSE("GPL");
> +
> +EXPORT_SYMBOL(i2c_8xx_add_bus);
> +EXPORT_SYMBOL(i2c_8xx_del_bus);
> +
> Index: 8xx/drivers/i2c/algos/Makefile
> ===================================================================
> --- 8xx.orig/drivers/i2c/algos/Makefile	2005-08-06 14:40:49.000000000 -0300
> +++ 8xx/drivers/i2c/algos/Makefile	2005-08-06 21:03:57.000000000 -0300
> @@ -8,6 +8,7 @@
>  obj-$(CONFIG_I2C_ALGOITE)	+= i2c-algo-ite.o
>  obj-$(CONFIG_I2C_ALGO_SIBYTE)	+= i2c-algo-sibyte.o
>  obj-$(CONFIG_I2C_ALGO_SGI)	+= i2c-algo-sgi.o
> +obj-$(CONFIG_I2C_ALGO8XX)	+= i2c-algo-8xx.o
>  
>  ifeq ($(CONFIG_I2C_DEBUG_ALGO),y)
>  EXTRA_CFLAGS += -DDEBUG
> Index: 8xx/include/linux/i2c-algo-8xx.h
> ===================================================================
> --- /dev/null	1970-01-01 00:00:00.000000000 +0000
> +++ 8xx/include/linux/i2c-algo-8xx.h	2005-08-06 21:03:57.000000000 -0300
> @@ -0,0 +1,28 @@
> +/* ------------------------------------------------------------------------- */
> +/* i2c-algo-8xx.h i2c driver algorithms for MPX8XX CPM			     */
> +/* ------------------------------------------------------------------------- */
> +
> +/* $Id$ */
> +
> +#ifndef I2C_ALGO_8XX_H
> +#define I2C_ALGO_8XX_H
> +
> +#include <linux/i2c.h>
> +#include <asm/8xx_immap.h>
> +#include <asm/commproc.h>
> +
> +struct i2c_algo_8xx_data {
> +	uint dp_addr;
> +	int reloc;
> +	volatile i2c8xx_t *i2c;
> +	volatile iic_t	*iip;
> +	volatile cpm8xx_t *cp;
> +
> +	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 */
> +




More information about the Linuxppc-embedded mailing list