linuxppc-dev.lists.ozlabs.org archive mirror
 help / color / mirror / Atom feed
* Re: MPC8260 I2C
@ 2004-11-16  8:06 miguel.valero
  2004-11-17 15:32 ` MPC85xx OCP->platform patches McMullan, Jason
  0 siblings, 1 reply; 2+ messages in thread
From: miguel.valero @ 2004-11-16  8:06 UTC (permalink / raw)
  To: Tom Rini; +Cc: sensors, linuxppc-embedded

[-- Attachment #1: Type: text/plain, Size: 2046 bytes --]

Tom,
thanks for your answer.
Yes, I am interested on having the MPC826x CPM i2c algorithm in the 
kernel.

Find the i2c-8260 patch enclosed.
I took Denx's 2.4.x based implementation and ported it to 2.6.7 and later 
to 2.6.9.

In addition, I have patched the i2c-dev.h as recommended by the lmsensors 
project in order to allow user space to perform ioctrl on the i2c device.

Regards.
Miguel

PS. I also have a patch for linux-2.6.7, if someone out there is 
interested








Tom Rini <trini@kernel.crashing.org>
15.11.04 19:49

 
        To:     miguel.valero@axxessit.no
        cc: 
        Subject:        Re: MPC8260 I2C


On Thu, Nov 11, 2004 at 05:20:11PM +0100, miguel.valero@axxessit.no wrote:

> Tom,
> you remember you asked me to see if I could rewrite the mpc8260 i2c 
driver 
> in an "i2c-mpc like" manner, by making use either of ocp or of 
> platform_devices setup.
> 
> I do not really know what you mean with "platform_devices setup", but I 
> have taken a look to the ocp stuff, and I realised that it is too riksy 
> for me to do the porting. I would most likely break the thing and spend 
a 
> lot of time debugging.

OK.

> The question is whether the community would accept the current 
> implementation with a specific bus driver, called PM826, and a specific 
> i2c algorithm, called i2c-algo-8260.
> 
> In the patch I have made, these 8260 bus and algo options are 
configurable 
> in drivers/i2c/busses/Kconfig and drivers/i2c/algos/Kconfig.

Probably, but the OCP or platform_device work is something that needs to
get at some point.  I'll take a look, if you're willing to push the
driver with upstream I2C folks.

[snip]
> My question to you is then: shall I send you (and the linuxppc-embedded 
> list) the patch ? Maybe someone else, more experienced than me in kernel 

> kacking, can do the rewritting faster at less risk, if it is considered 
> necessary ?

The I2C list is at sensors@stimpy.netroedge.com, and should probably be
CC'd as well.

Thanks again.

-- 
Tom Rini
http://gate.crashing.org/~trini/



[-- Attachment #2: linux-2.6.9-i2c-8260.patch --]
[-- Type: application/octet-stream, Size: 45226 bytes --]

--- linux-2.6.9/drivers/i2c/algos/i2c-algo-8260.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.9.axxmetro/drivers/i2c/algos/i2c-algo-8260.c	2004-11-08 10:09:56.000000000 +0100
@@ -0,0 +1,599 @@
+/*
+ * i2c-algo-8260.c i2x driver algorithms for MPC8260 CPM
+ * Derived from "i2c-algo-8xx.c":
+ * Copyright (c) 1999 Dan Malek (dmalek@jlc.net).
+ * (C) 2001 Wolfgang Denk, wd@denx.de
+ *
+ * moved into proper i2c interface; separated out platform specific 
+ * parts into i2c-rpx.c
+ * Brad Parker (brad@heeltoe.com)
+ */
+
+#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/mpc8260.h>
+#include <asm/immap_cpm2.h>
+#include <asm/cpm2.h>
+#include <asm/irq.h>
+
+#include <linux/i2c.h>
+#include <linux/i2c-algo-8260.h>
+
+#define CPM_MAX_READ	513
+
+/* imported from arch/ppc/kernel/misc.S */
+extern void invalidate_dcache_range(ulong start, ulong stop);
+
+static wait_queue_head_t iic_wait;
+static ushort r_tbase, r_rbase;
+static u_char iic_int_recd;
+
+int cpm_scan = 0;
+int cpm_debug = 0;
+
+static irqreturn_t
+cpm_iic_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	volatile i2c_cpm2_t *i2c = (i2c_cpm2_t *)dev_id;
+
+	if (cpm_debug > 1)
+		printk(KERN_INFO "cpm_iic_interrupt(dev_id=%p)\n", dev_id);
+
+	/* Clear interrupt.
+	*/
+	i2c->i2c_i2cer = 0xff;
+	/* Mark interrupt received.
+	*/
+	iic_int_recd = 1;
+	/* Get 'me going again.
+	*/
+	wake_up_interruptible(&iic_wait);
+
+	return IRQ_HANDLED;
+}
+
+static void
+cpm_iic_init(struct i2c_algo_8260_data *cpm_adap)
+{
+	volatile iic_t		*iip = cpm_adap->iip;
+	volatile i2c_cpm2_t	*i2c = cpm_adap->i2c;
+
+	if (cpm_debug)
+		printk(KERN_INFO "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 = CPMFCR_GBL | CPMFCR_EB;
+	iip->iic_rfcr = CPMFCR_GBL | CPMFCR_EB;
+
+	/* Set maximum receive size.
+	*/
+	iip->iic_mrblr = CPM_MAX_READ;
+
+	/* Initialize Tx/Rx parameters.
+	*/
+	{
+		volatile cpm_cpm2_t *cp = cpm_adap->cp;
+
+		cp->cp_cpcr =
+			mk_cr_cmd(CPM_CR_I2C_PAGE, CPM_CR_I2C_SBLOCK, 0x00, CPM_CR_INIT_TRX) | CPM_CR_FLG;
+		while (cp->cp_cpcr & CPM_CR_FLG);
+	}
+
+	/* Select an arbitrary address.  Just make sure it is unique.
+	*/
+	i2c->i2c_i2add = 0x34;
+
+	/* Divider is 2 * ( 15 + 3 )
+	*/
+	i2c->i2c_i2brg = 0x0f;
+
+	/* Pre-divider is BRGCLK/4
+	 */
+	i2c->i2c_i2mod = 0x06;
+
+	/* Disable interrupts.
+	*/
+	i2c->i2c_i2cmr = 0;
+	i2c->i2c_i2cer = 0xff;
+
+	init_waitqueue_head(&iic_wait);
+
+	/* Install interrupt handler.
+	*/
+	if (cpm_debug) {
+		printk (KERN_INFO "cpm_iic_init(): Install ISR for IRQ %d\n", SIU_INT_I2C);
+	}
+	(*cpm_adap->setisr)(SIU_INT_I2C, cpm_iic_interrupt, (void *)i2c);
+}
+
+
+static int
+cpm_iic_shutdown(struct i2c_algo_8260_data *cpm_adap)
+{
+	volatile i2c_cpm2_t *i2c = cpm_adap->i2c;
+
+	/* Shut down IIC.
+	*/
+	i2c->i2c_i2mod = 0;
+	i2c->i2c_i2cmr = 0;
+	i2c->i2c_i2cer = 0xff;
+
+	return(0);
+}
+
+#if (0)
+static void
+cpm_reset_iic_params(volatile iic_t *iip)
+{
+	iip->iic_tbase = r_tbase;
+	iip->iic_rbase = r_rbase;
+
+	iip->iic_tfcr = CPMFCR_GBL | CPMFCR_EB;
+	iip->iic_rfcr = CPMFCR_GBL | CPMFCR_EB;
+
+	iip->iic_mrblr = CPM_MAX_READ;
+
+	iip->iic_rstate = 0;
+	iip->iic_rdp = 0;
+	iip->iic_rbptr = 0;
+	iip->iic_rbc = 0;
+	iip->iic_rxtmp = 0;
+	iip->iic_tstate = 0;
+	iip->iic_tdp = 0;
+	iip->iic_tbptr = 0;
+	iip->iic_tbc = 0;
+	iip->iic_txtmp = 0;
+}
+#endif
+
+#define BD_SC_NAK		((ushort)0x0004) /* NAK - did not respond */
+#define CPM_CR_CLOSE_RXBD	((ushort)0x0007)
+
+static void force_close(struct i2c_algo_8260_data *cpm)
+{
+#if 0
+	volatile cpm_cpm2_t *cp = cpm->cp;
+#endif
+	if (cpm_debug) printk(KERN_INFO "force_close()\n");
+#if 0
+	cp->cp_cpcr =
+		mk_cr_cmd(CPM_CR_CH_I2C, CPM_CR_CLOSE_RXBD) |
+		CPM_CR_FLG;
+
+	while (cp->cp_cpcr & CPM_CR_FLG);
+#endif
+}
+
+
+/* Read from IIC...
+ * abyte = address byte, with r/w flag already set
+ */
+static
+int cpm_iic_read(struct i2c_algo_8260_data *cpm, u_char abyte, char *buf, int count)
+{
+	volatile cpm2_map_t *immap = (cpm2_map_t *)IMAP_ADDR;
+	volatile iic_t *iip = cpm->iip;
+	volatile i2c_cpm2_t *i2c = cpm->i2c;
+	volatile cbd_t	*tbdf, *rbdf;
+	u_char *tb;
+	unsigned long flags;
+	int interrupted;
+
+	if (count >= CPM_MAX_READ)
+		return -EINVAL;
+
+	tbdf = (cbd_t *)&immap->im_dprambase[iip->iic_tbase];
+	rbdf = (cbd_t *)&immap->im_dprambase[iip->iic_rbase];
+
+	/* To read, we need an empty buffer of the proper length.
+	 * All that is used is the first byte for address, the remainder
+	 * is just used for timing (and doesn't really have to exist).
+	 */
+#if (0)
+	if (/*cpm->reloc*/0) {
+		cpm_reset_iic_params(iip);
+	}
+#endif
+	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_INFO "cpm_iic_read(abyte=0x%x)\n", abyte);
+
+	tbdf->cbd_bufaddr = __pa(tb);
+	tbdf->cbd_datlen = count + 1;
+	tbdf->cbd_sc =
+		BD_SC_READY | BD_SC_INTRPT | BD_SC_LAST |
+		BD_SC_WRAP | BD_IIC_START;
+
+	rbdf->cbd_datlen = 0;
+	rbdf->cbd_bufaddr = __pa(buf);
+	rbdf->cbd_sc = BD_SC_EMPTY | BD_SC_WRAP;
+
+	if (count > 0 && count < CPM_MAX_READ)
+		iip->iic_mrblr = count;	/* prevent excessive read */
+
+	invalidate_dcache_range((unsigned int)buf, (unsigned int)(buf+count));
+
+	/* Reset interrupt received mark */
+        iic_int_recd = 0;
+
+	/* 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 = 0x81;	/* Start master */
+
+	/* Wait for IIC transfer */
+	interrupted = wait_event_interruptible_timeout(
+				iic_wait, iic_int_recd, (1*HZ)/100);
+	local_irq_restore(flags);
+	if (signal_pending(current))
+		return -EIO;
+	if (!interrupted)
+		return -ETIMEDOUT;
+
+	if (cpm_debug) {
+		printk(KERN_INFO "tx sc %04x, rx sc %04x\n",
+		       tbdf->cbd_sc, rbdf->cbd_sc);
+	}
+
+	if (tbdf->cbd_sc & BD_SC_NAK) {
+		printk(KERN_INFO "IIC read; no ack\n");
+		return 0;
+	}
+
+	if (rbdf->cbd_sc & BD_SC_EMPTY) {
+		printk(KERN_INFO "IIC read; complete but rbuf empty\n");
+		force_close(cpm);
+		printk(KERN_INFO "tx sc %04x, rx sc %04x\n",
+		       tbdf->cbd_sc, rbdf->cbd_sc);
+	}
+
+	if (cpm_debug) 
+		printk(KERN_INFO "read %d bytes\n", rbdf->cbd_datlen);
+
+	if (rbdf->cbd_datlen < count) {
+		printk(KERN_INFO "IIC read; short, wanted %d got %d\n",
+		       count, rbdf->cbd_datlen);
+		return 0;
+	}
+	if (cpm_debug) 
+		printk(KERN_INFO "buf[0] = 0x%x\n", buf[0]);
+
+
+	return count;
+}
+
+/* Write to IIC...
+ * addr = address byte, with r/w flag already set
+ */
+static
+int cpm_iic_write(struct i2c_algo_8260_data *cpm, u_char abyte, char *buf,int count)
+{
+	volatile cpm2_map_t *immap = (cpm2_map_t *)IMAP_ADDR;
+	volatile iic_t *iip = cpm->iip;
+	volatile i2c_cpm2_t *i2c = cpm->i2c;
+	volatile cbd_t	*tbdf;
+	u_char *tb;
+	unsigned long flags;
+        int interrupted;
+
+	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_INFO "cpm_iic_write(abyte=0x%x)\n", abyte);
+	if (cpm_debug) 
+		printk(KERN_INFO "buf[0] = 0x%x, buf[1] = 0x%x\n", buf[0], buf[1]);
+
+	/* set up 2 descriptors */
+	tbdf = (cbd_t *)&immap->im_dprambase[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;
+
+        /* Reset interrupt received mark */
+        iic_int_recd = 0;
+
+	/* 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 = 0x81;	/* Start master */
+
+	/* Wait for IIC transfer */
+        interrupted = wait_event_interruptible_timeout(
+				iic_wait, iic_int_recd, (1*HZ)/100);
+        local_irq_restore(flags);
+        if (signal_pending(current))
+                return -EIO;
+        if (!interrupted)
+                return -ETIMEDOUT;
+
+	if (cpm_debug) {
+		printk(KERN_INFO "tx0 sc %04x, tx1 sc %04x\n",
+		       tbdf[0].cbd_sc, tbdf[1].cbd_sc);
+	}
+
+	if (tbdf->cbd_sc & BD_SC_NAK) {
+		printk(KERN_INFO "IIC write; no ack\n");
+		return 0;
+	}
+
+	if (tbdf->cbd_sc & BD_SC_READY) {
+		printk(KERN_INFO "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_8260_data *cpm, int addr)
+{
+	volatile cpm2_map_t *immap = (cpm2_map_t *)IMAP_ADDR;
+	volatile iic_t *iip = cpm->iip;
+	volatile i2c_cpm2_t *i2c = cpm->i2c;
+	volatile cbd_t *tbdf, *rbdf;
+	u_char *tb;
+	unsigned long flags, len;
+        int interrupted;
+
+	if (cpm_debug > 1)
+		printk(KERN_INFO "cpm_iic_tryaddress(cpm=%p,addr=%d)\n", cpm, addr);
+
+	if (cpm_debug && addr == 0) {
+		printk(KERN_INFO "iip %p, dp_addr 0x%x\n", cpm->iip, cpm->dp_addr);
+		printk(KERN_INFO "iic_tbase %d, r_tbase %d\n", iip->iic_tbase, r_tbase);
+	}
+
+	tbdf = (cbd_t *)&immap->im_dprambase[iip->iic_tbase];
+	rbdf = (cbd_t *)&immap->im_dprambase[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_INTRPT | BD_SC_LAST |
+		BD_SC_WRAP | BD_IIC_START;
+
+	rbdf->cbd_datlen = 0;
+	rbdf->cbd_bufaddr = __pa(tb+2);
+	rbdf->cbd_sc = BD_SC_EMPTY | BD_SC_WRAP;
+
+        /* Reset interrupt received mark */
+        iic_int_recd = 0;
+
+        local_irq_save(flags);
+	i2c->i2c_i2cmr = 0x13;	/* Enable some interupts */
+	i2c->i2c_i2cer = 0xff;
+	i2c->i2c_i2mod |= 1;	/* Enable */
+	i2c->i2c_i2com = 0x81;	/* Start master */
+
+	if (cpm_debug > 1) 
+		printk(KERN_INFO "about to sleep\n");
+
+	/* wait for IIC transfer */
+        interrupted = wait_event_interruptible_timeout(
+				iic_wait, iic_int_recd, (1*HZ)/100);
+        local_irq_restore(flags);
+        if (signal_pending(current))
+                return -EIO;
+        if (!interrupted)
+                return -ETIMEDOUT;
+
+	if (cpm_debug > 1) 
+		printk(KERN_INFO "back from sleep\n");
+
+	if (tbdf->cbd_sc & BD_SC_NAK) {
+		if (cpm_debug > 1) 
+			printk(KERN_INFO "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_8260_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 (pmsg->len) {
+      /* Do the transfer only if there is something to transfer ! */
+  		if (cpm_debug)
+	  		printk(KERN_INFO "i2c-algo-8260.o: "
+		  	       "#%d addr=0x%x flags=0x%x len=%d\n",
+			         i, pmsg->addr, pmsg->flags, pmsg->len);
+
+  		addr = pmsg->addr << 1;
+	  	if (pmsg->flags & I2C_M_RD )
+		  	addr |= 1;
+  		if (pmsg->flags & I2C_M_REV_DIR_ADDR )
+	  		addr ^= 1;
+
+		  if (!(pmsg->flags & I2C_M_NOSTART)) {
+  		}
+	  	if (pmsg->flags & I2C_M_RD ) {
+		  	/* read bytes into buffer*/
+			  ret = cpm_iic_read(adap, addr, pmsg->buf, pmsg->len);
+  			if (cpm_debug)
+	  			printk(KERN_INFO "i2c-algo-8260.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_INFO "i2c-algo-8260.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 = {
+	.name		        = "MPC8260 CPM algorithm",
+	.id		          = I2C_ALGO_MPC8260,
+	.master_xfer	  = cpm_xfer,
+	.algo_control   = algo_control,			/* ioctl		*/
+	.functionality	= cpm_func			/* functionality	*/
+};
+
+/*
+ * registering functions to load algorithms at runtime
+ */
+int i2c_8260_add_bus(struct i2c_adapter *adap)
+{
+	int i;
+	struct i2c_algo_8260_data *cpm_adap = adap->algo_data;
+
+	if (cpm_debug)
+		printk(KERN_INFO "i2c-algo-8260.o: hw routines for %s registered.\n",
+		       adap->name);
+
+	/* register new adapter to i2c module... */
+
+	adap->id |= cpm_algo.id;
+	adap->algo = &cpm_algo;
+
+	cpm_iic_init(cpm_adap);
+	i2c_add_adapter(adap);
+
+	/* scan bus */
+	if (cpm_scan) {
+		printk(KERN_INFO " i2c-algo-8260.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_8260_del_bus(struct i2c_adapter *adap)
+{
+	int res;
+	struct i2c_algo_8260_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-8260.o: adapter unregistered: %s\n",adap->name);
+
+	return 0;
+}
+
+EXPORT_SYMBOL(i2c_8260_add_bus);
+EXPORT_SYMBOL(i2c_8260_del_bus);
+
+int __init i2c_algo_8260_init (void)
+{
+	printk(KERN_INFO "i2c MPC8260 algorithm module\n");
+	return 0;
+}
+
+
+MODULE_AUTHOR("Brad Parker <brad@heeltoe.com>");
+MODULE_DESCRIPTION("I2C-Bus MPC8260 algorithm");
+MODULE_LICENSE("GPL");
+
+int i2c_algo_8260_init_module(void) 
+{
+	return i2c_algo_8260_init();
+}
+
+void i2c_algo_8260_cleanup_module(void) 
+{
+}
+
+module_init(i2c_algo_8260_init_module);
+module_exit(i2c_algo_8260_cleanup_module);
--- linux-2.6.9/drivers/i2c/algos/Makefile	2004-10-18 23:54:40.000000000 +0200
+++ linux-2.6.9.axxmetro/drivers/i2c/algos/Makefile	2004-11-08 10:09:56.000000000 +0100
@@ -6,6 +6,7 @@ obj-$(CONFIG_I2C_ALGOBIT)	+= i2c-algo-bi
 obj-$(CONFIG_I2C_ALGOPCF)	+= i2c-algo-pcf.o
 obj-$(CONFIG_I2C_ALGOPCA)	+= i2c-algo-pca.o
 obj-$(CONFIG_I2C_ALGOITE)	+= i2c-algo-ite.o
+obj-$(CONFIG_I2C_ALGO8260)	+= i2c-algo-8260.o
 
 ifeq ($(CONFIG_I2C_DEBUG_ALGO),y)
 EXTRA_CFLAGS += -DDEBUG
--- linux-2.6.9/drivers/i2c/algos/Kconfig	2004-10-18 23:54:55.000000000 +0200
+++ linux-2.6.9.axxmetro/drivers/i2c/algos/Kconfig	2004-11-08 10:09:56.000000000 +0100
@@ -53,5 +53,14 @@ config I2C_ALGO8XX
 	tristate "MPC8xx CPM I2C interface"
 	depends on 8xx && I2C
 
+config I2C_ALGO8260
+        tristate "MPC8260 CPM I2C interface"
+        depends on 8260 && I2C
+        select I2C_PM8260
+        help
+
+          If you say yes to this option, support will be included for the
+          MPC8260 CPM I2C interface.
+
 endmenu
 
--- linux-2.6.9/drivers/i2c/busses/i2c-pm826.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.9.axxmetro/drivers/i2c/busses/i2c-pm826.c	2004-11-08 10:09:56.000000000 +0100
@@ -0,0 +1,112 @@
+/*
+ * PM826 CPM I2C interface.
+ * Copyright (c) 2001 DENX Software Engineering, Wolfgang Denk, wd@denx.de
+ *
+ * PM826 specific parts of the i2c interface
+ */
+
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/stddef.h>
+#include <linux/parport.h>
+#include <linux/interrupt.h>
+
+#include <asm/mpc8260.h>
+#include <asm/immap_cpm2.h>
+#include <asm/cpm2.h>
+
+#include <linux/i2c.h>
+#include <linux/i2c-algo-8260.h>
+
+static void
+pm826_iic_init(struct i2c_algo_8260_data *data)
+{
+	volatile cpm_cpm2_t *cp;
+	volatile cpm2_map_t *immap;
+
+	cp = cpmp;	/* Get pointer to Communication Processor */
+	immap = (cpm2_map_t *)IMAP_ADDR;	/* and to internal registers */
+
+	*(ushort *)(&immap->im_dprambase[PROFF_I2C_BASE]) = PROFF_I2C;
+	data->iip = (iic_t *)&immap->im_dprambase[PROFF_I2C];
+
+	data->i2c = (i2c_cpm2_t *)&(immap->im_i2c);
+	data->cp = cp;
+
+	/* Initialize Port D IIC pins.
+	*/
+	immap->im_ioport.iop_ppard |= 0x00030000;
+	immap->im_ioport.iop_pdird &= ~0x00030000;
+	immap->im_ioport.iop_podrd |= 0x00030000;
+	immap->im_ioport.iop_psord |= 0x00030000;
+
+	/* Allocate space for two transmit and two receive buffer
+	 * descriptors in the DP ram.
+	 */
+	data->dp_addr = cpm_dpalloc(sizeof(cbd_t) * 4, 8);
+
+	/* ptr to i2c area */
+	data->i2c = (i2c_cpm2_t *)&(((cpm2_map_t *)IMAP_ADDR)->im_i2c);
+}
+
+static int pm826_install_isr(int irq,
+                             irqreturn_t (*func)(int, void *, struct pt_regs *),
+                             void *data)
+{
+	/* install interrupt handler */
+	request_irq(irq, func, 	0, "i2c", data);
+
+	return 0;
+}
+
+static int pm826_reg(struct i2c_client *client)
+{
+	return 0;
+}
+
+static int pm826_unreg(struct i2c_client *client)
+{
+	return 0;
+}
+
+static struct i2c_algo_8260_data pm826_data = {
+	setisr: pm826_install_isr
+};
+
+
+static struct i2c_adapter pm826_ops = {
+	.owner      = THIS_MODULE,
+	.class      = I2C_HW_MPC8260_PM826,
+	.algo_data  = &pm826_data,
+	.client_register  = pm826_reg,
+	.client_unregister= pm826_unreg,
+	.name       = "pm826"
+};
+
+int __init i2c_pm826_init(void)
+{
+	printk(KERN_INFO "i2c PM826 module\n");
+
+	/* reset hardware to sane state */
+	pm826_iic_init(&pm826_data);
+
+	if (i2c_8260_add_bus(&pm826_ops) < 0) {
+		printk(KERN_INFO "i2c-pm826: Unable to register with I2C\n");
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+void __exit i2c_pm826_exit(void)
+{
+	i2c_8260_del_bus(&pm826_ops);
+}
+
+MODULE_AUTHOR("Wolfgang Denk <wd@denx.de>");
+MODULE_DESCRIPTION("I2C-Bus adapter routines for PM826");
+
+module_init(i2c_pm826_init);
+module_exit(i2c_pm826_exit);
--- linux-2.6.9/drivers/i2c/busses/Makefile	2004-10-18 23:53:11.000000000 +0200
+++ linux-2.6.9.axxmetro/drivers/i2c/busses/Makefile	2004-11-08 10:09:56.000000000 +0100
@@ -35,6 +35,7 @@ obj-$(CONFIG_I2C_VIAPRO)	+= i2c-viapro.o
 obj-$(CONFIG_I2C_VOODOO3)	+= i2c-voodoo3.o
 obj-$(CONFIG_SCx200_ACB)	+= scx200_acb.o
 obj-$(CONFIG_SCx200_I2C)	+= scx200_i2c.o
+obj-$(CONFIG_I2C_PM8260)	+= i2c-pm826.o
 
 ifeq ($(CONFIG_I2C_DEBUG_BUS),y)
 EXTRA_CFLAGS += -DDEBUG
--- linux-2.6.9/drivers/i2c/busses/Kconfig	2004-10-18 23:55:06.000000000 +0200
+++ linux-2.6.9.axxmetro/drivers/i2c/busses/Kconfig	2004-11-08 10:09:56.000000000 +0100
@@ -430,4 +430,12 @@ config I2C_PCA_ISA
 	  This driver can also be built as a module.  If so, the module
 	  will be called i2c-pca-isa.
 
+config I2C_PM8260
+        tristate "MPC8260 CPM I2C interface"
+        depends on 8260 && I2C && I2C_ALGO8260
+        help
+
+          If you say yes to this option, support will be included for the
+          MPC8260 CPM I2C interface.
+
 endmenu
--- linux-2.6.9/drivers/i2c/chips/ds1340.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.9.axxmetro/drivers/i2c/chips/ds1340.c	2004-11-08 10:09:56.000000000 +0100
@@ -0,0 +1,273 @@
+/*
+ * linux/drivers/i2c/ds1340.c
+ *
+ * Author: Miguel Valero <miguel.valero@axxessit.no>
+ *
+ * Linux support for the MAXIM DS1340 Serial Real-Time Clock.
+ *
+ * This source code is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * Behaviour of the OSF (Oscillator Stop Flag) and EOSC (Enable Oscillator)
+ *
+ * OSF=1 if either
+ *    First time power up
+ *    EOSC=1 (oscillator disabled)
+ *    Vcc and Battery failed
+ *    External influences
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/miscdevice.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/rtc.h>
+#include <asm/semaphore.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/machdep.h>
+#include <asm/rtc.h>
+#include <asm/cache.h>
+
+#define BCD_TO_BIN(x) (((x) & 15) + ((x) >> 4) * 10)
+#define BIN_TO_BCD(x) ((((x) / 10) << 4) + (x) % 10)
+
+/* Addresses to scan */
+static unsigned short normal_i2c[] = { 0x68, I2C_CLIENT_END };
+static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
+
+I2C_CLIENT_INSMOD;
+
+static struct i2c_driver rtc_driver;
+
+#define I2C_DRIVERID_RTC_DS1340 48
+
+static struct i2c_client client;
+
+/*
+ * The MAXIM DS1340 Real-Time Clock wants the address in a different
+ * message, so we can't use the normal i2c_master_recv() routine
+ * for receiving data.
+ */
+static
+int rtc_ds1340_i2c_recv(struct i2c_client *client,
+                               char *buf, char addr, int count)
+{
+  struct i2c_msg msg[2];
+  /* The MPC8260 i2c algorithm flushes data cache blocks of
+     L1_CACHE_LINE_SIZE bytes, so make sure that the stack does
+     not get corrupted by allocating big enough buffers */
+  char local_buf[2 * L1_CACHE_LINE_SIZE];
+  int result = 0;
+
+  local_buf[0] = addr;
+  /* First i2c buffer is to write the register pointer in the DS1340 */
+  msg[0].addr = client->addr;
+  msg[0].flags = 0;
+  msg[0].len = 1;
+  msg[0].buf = local_buf;
+  /* Second i2c buffer is to read from the DS1340 */
+  msg[1].addr = client->addr;          
+  msg[1].flags = I2C_M_RD;
+  msg[1].len = count;
+  msg[1].buf = &local_buf[L1_CACHE_LINE_SIZE];
+  
+  if (i2c_transfer(client->adapter, msg, 2) != 2)
+    result = -EIO;
+  memcpy(buf, &local_buf[L1_CACHE_LINE_SIZE], count);
+  
+  return result;
+}
+
+static
+int rtc_ds1340_setup(void)
+{
+  /* The MPC8260 i2c algorithm flushes data cache blocks of
+     L1_CACHE_LINE_SIZE bytes, so make sure that the stack does
+     not get corrupted by allocating big enough buffers */
+  char buf[L1_CACHE_LINE_SIZE];
+  
+  memset(buf, 0, L1_CACHE_LINE_SIZE);
+  if (rtc_ds1340_i2c_recv(&client, buf, 0x09, 1) < 0)
+    return -EIO;
+#if (0)
+  printk("read addr[9]=%02x\n", buf[0]);
+#endif
+  /* Check and clear the OSF bit */
+  if(buf[0] & 0x80) {
+    printk(KERN_INFO "RTC is stopped (OSF)\n");
+
+    memset(buf, 0, L1_CACHE_LINE_SIZE);
+    if (rtc_ds1340_i2c_recv(&client, buf, 0x00, 1) < 0)
+      return -EIO;
+    #if (0)
+      printk("read addr[0]=%02x\n", buf[1]);
+    #endif
+    if (buf[0] & 0x80) {
+      printk(KERN_INFO "RTC is disabled (EOSC): we will enable it now\n");
+      
+      buf[0] = 0x00;
+      buf[1] &= ~0x80;
+
+      if(i2c_master_send(&client, buf, 2) != 2)
+        return -EIO;
+    }
+    /* Clear OSF bit */
+    buf[0] = 0x09;
+    buf[1] = 0x00;
+
+    if(i2c_master_send(&client, buf, 2) != 2)
+      return -EIO;
+  }
+
+  return 0;
+}
+
+unsigned int rtc_ds1340_get_time(struct rtc_time *time)
+{
+  char buf1[2], buf2[10];
+
+  /* The only way to tell the user that rtc time is not reliable (?) */
+  if (client.id == 0)
+    return RTC_24H | RTC_BATT_BAD;
+
+  memset(buf1, 0, 2);
+  memset(buf2, 0, 10);
+
+  if (rtc_ds1340_i2c_recv(&client, buf1, 0x09, 1) < 0)
+    return -RTC_24H | RTC_BATT_BAD;
+
+  if (rtc_ds1340_i2c_recv(&client, buf2, 0x00, 8) < 0)
+    return -RTC_24H | RTC_BATT_BAD;
+#if (0)
+  printk("read addr[9]=%02x\n", buf1[0]);
+  printk("read addr[0]=%02x, %02x, %02x, %02x, %02x, %02x, %02x, %02x\n",
+          buf2[0], buf2[1], buf2[2], buf2[3], buf2[4], buf2[5], buf2[6], buf2[7]);
+#endif
+  time->tm_sec = BCD_TO_BIN(buf2[0] & 0x7F);
+  time->tm_min = BCD_TO_BIN(buf2[1] & 0x7F);
+  time->tm_hour = BCD_TO_BIN(buf2[2] & 0x3f);
+  time->tm_wday = BCD_TO_BIN(buf2[3] & 0x07) - 1;
+  time->tm_mday = BCD_TO_BIN(buf2[4] & 0x3F);
+  time->tm_mon = BCD_TO_BIN(buf2[5] & 0x1F) - 1;
+  time->tm_year = BCD_TO_BIN(buf2[6]) + 100;
+
+  /* Always 24h mode; check OSF bit to see if oscillator is stopped (time was lost) */
+  return RTC_24H | (buf1[0] & 0x80 ? RTC_BATT_BAD : 0);
+}
+
+int rtc_ds1340_set_time(struct rtc_time *time)
+{
+  /* The MPC8260 i2c algorithm flushes data cache blocks of
+     L1_CACHE_LINE_SIZE bytes, so make sure that the stack does
+     not get corrupted by allocating big enough buffers */
+  char buf[L1_CACHE_LINE_SIZE];
+
+  if(client.id == 0)
+    return -ENODEV;
+
+  /* Now set the new time, select address 0 */
+  buf[0] = 0x00;
+
+  buf[1] = BIN_TO_BCD(time->tm_sec) & 0x7F; /* Make sure EOSC (bit 7) is 0 */
+  buf[2] = BIN_TO_BCD(time->tm_min) & 0x7F;
+  buf[3] = BIN_TO_BCD(time->tm_hour) & 0x3F;
+
+  buf[4] = BIN_TO_BCD(time->tm_wday + 1) & 0x07;
+  buf[5] = BIN_TO_BCD(time->tm_mday) & 0x3F;
+  buf[6] = BIN_TO_BCD(time->tm_mon + 1) & 0x1F;
+  buf[7] = BIN_TO_BCD(time->tm_year - 100);
+
+  /* Note that this is atomic since the i2c layer has a lock for xfers */
+  if(i2c_master_send(&client, buf, 8) != 8)
+    return -EIO;
+
+  return 0;
+}
+
+int rtc_ds1340_set_rtc_time(unsigned long nowtime)
+{
+  struct rtc_time wtime;
+
+  printk("rtc_ds1340_set_rtc_time(): 11 minutes\n");
+  to_tm(nowtime, &wtime);
+
+  /* wtime probably needs some fiddling here (year -= 1900 etc.) */
+
+  return rtc_ds1340_set_time(&wtime);
+}
+
+int rtc_ds1340_detect(struct i2c_adapter *adapter, int address, int kind)
+{
+  int err = 0;
+
+  client.addr = address;
+  client.adapter = adapter;
+  client.driver = &rtc_driver;
+  strcpy(client.name, rtc_driver.name);
+  client.flags = 0; /* no "use" allowed (conflicts with this_client) */
+  client.id = rtc_driver.id;
+    /* Tell the I2C layer a new client has arrived */
+  if ((err = i2c_attach_client(&client)))
+    goto ERROR;
+
+  if(rtc_ds1340_setup() < 0)
+    goto ERROR;
+
+  /* Hook up the wrapper to machdep for 11-minute mode support */
+  ppc_md.set_rtc_time = rtc_ds1340_set_rtc_time;
+
+  return 0;
+
+ERROR:
+  return err;
+}
+
+static
+int rtc_ds1340_attach_adapter(struct i2c_adapter *adapter)
+{
+  return i2c_probe(adapter, &addr_data, rtc_ds1340_detect);
+}
+
+static int rtc_ds1340_detach_client(struct i2c_client *client)
+{
+  i2c_detach_client(client);
+  
+  return 0;
+}
+
+static struct i2c_driver rtc_driver = {
+  .owner          = THIS_MODULE,
+  .name           = "ds1340",
+  .id             = I2C_DRIVERID_RTC_DS1340,
+  .flags          = I2C_DF_NOTIFY,
+  .attach_adapter = rtc_ds1340_attach_adapter,
+  .detach_client  = rtc_ds1340_detach_client,
+};
+
+static int __init rtc_ds1340_init(void)
+{
+  int rc;
+  memset(&client, 0, sizeof(struct i2c_client));
+  rc = i2c_add_driver(&rtc_driver);
+  return rc;
+}
+
+static void __exit rtc_ds1340_exit(void)
+{
+  i2c_del_driver(&rtc_driver);
+}
+
+
+MODULE_LICENSE ("GPL");
+MODULE_AUTHOR ("Miguel Valero <miguel.valero@axxessit.no>");
+MODULE_DESCRIPTION ("MAXIM DS1340 Real-Time Clock driver");
+
+module_init(rtc_ds1340_init);
+module_exit(rtc_ds1340_exit);
--- linux-2.6.9/drivers/i2c/chips/Makefile	2004-10-18 23:55:36.000000000 +0200
+++ linux-2.6.9.axxmetro/drivers/i2c/chips/Makefile	2004-11-08 10:09:56.000000000 +0100
@@ -30,6 +30,7 @@ obj-$(CONFIG_SENSORS_SMSC47M1)	+= smsc47
 obj-$(CONFIG_SENSORS_VIA686A)	+= via686a.o
 obj-$(CONFIG_SENSORS_W83L785TS)	+= w83l785ts.o
 obj-$(CONFIG_ISP1301_OMAP)	+= isp1301_omap.o
+obj-$(CONFIG_SENSORS_DS1340)	+= ds1340.o
 
 ifeq ($(CONFIG_I2C_DEBUG_CHIP),y)
 EXTRA_CFLAGS += -DDEBUG
--- linux-2.6.9/drivers/i2c/chips/Kconfig	2004-10-18 23:54:31.000000000 +0200
+++ linux-2.6.9.axxmetro/drivers/i2c/chips/Kconfig	2004-11-08 10:09:56.000000000 +0100
@@ -251,6 +251,16 @@ config SENSORS_W83627HF
 	  This driver can also be built as a module.  If so, the module
 	  will be called w83627hf.
 
+config SENSORS_DS1340
+        tristate "Dallas Semiconductor 1340 RTC chip"
+        depends on I2C
+        select I2C_SENSOR
+        help
+          If you say yes here you get support for the DS1340 RTC chip.
+                                                                                
+          This driver can also be built as a module.  If so, the module
+          will be called i2c-ds1340.
+
 endmenu
 
 menu "Other I2C Chip support"
--- linux-2.6.9/include/asm-ppc/cpm2.h	2004-10-18 23:54:07.000000000 +0200
+++ linux-2.6.9.axxmetro/include/asm-ppc/cpm2.h	2004-11-08 10:09:56.000000000 +0100
@@ -177,6 +177,7 @@ typedef struct cpm_buf_desc {
  */
 #define PROFF_SMC1	(0)
 #define PROFF_SMC2	(64)
+#define PROFF_I2C		((16 * 1024) - 64)
 
 
 /* Define enough so I can at least use the serial port as a UART.
--- linux-2.6.9/include/linux/i2c-algo-8260.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.9.axxmetro/include/linux/i2c-algo-8260.h	2004-11-08 10:09:56.000000000 +0100
@@ -0,0 +1,28 @@
+/* ------------------------------------------------------------------------- */
+/* i2c-algo-8260.h i2c driver algorithms for MPX8260 CPM		     */
+/* ------------------------------------------------------------------------- */
+
+#ifndef I2C_ALGO_8260_H
+#define I2C_ALGO_8260_H 1
+
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+
+struct i2c_algo_8260_data {
+	uint dp_addr;
+	int reloc;
+	volatile i2c_cpm2_t *i2c;
+	volatile iic_t	*iip;
+	volatile cpm_cpm2_t *cp;
+
+	int	(*setisr) (int irq,
+			   irqreturn_t (*func)(int, void *, struct pt_regs *),
+			   void *data);
+
+	u_char	temp[513];
+};
+
+int i2c_8260_add_bus(struct i2c_adapter *);
+int i2c_8260_del_bus(struct i2c_adapter *);
+
+#endif /* I2C_ALGO_8260_H */
--- linux-2.6.9/include/linux/i2c-dev.h	2004-10-18 23:53:44.000000000 +0200
+++ linux-2.6.9.axxmetro/include/linux/i2c-dev.h	2004-11-08 10:09:56.000000000 +0100
@@ -25,6 +25,9 @@
 #define _LINUX_I2C_DEV_H
 
 #include <linux/types.h>
+#include <linux/compiler.h>
+
+#ifdef __KERNEL__
 
 /* Some IOCTL commands are defined in <linux/i2c.h> */
 /* Note: 10-bit addresses are NOT supported! */
@@ -45,4 +48,342 @@ struct i2c_rdwr_ioctl_data {
 
 #define  I2C_RDRW_IOCTL_MAX_MSGS	42
 
+#else
+
+#include <sys/ioctl.h>
+
+
+/* -- i2c.h -- */
+
+
+/*
+ * I2C Message - used for pure i2c transaction, also from /dev interface
+ */
+struct i2c_msg {
+	__u16 addr;	/* slave address			*/
+ 	__u16 flags;
+#define I2C_M_TEN	0x10	/* we have a ten bit chip address	*/
+#define I2C_M_RD	0x01
+#define I2C_M_NOSTART	0x4000
+#define I2C_M_REV_DIR_ADDR	0x2000
+#define I2C_M_IGNORE_NAK	0x1000
+#define I2C_M_NO_RD_ACK		0x0800
+ 	__u16 len;		/* msg length				*/
+ 	__u8 *buf;		/* pointer to msg data			*/
+};
+
+/* To determine what functionality is present */
+
+#define I2C_FUNC_I2C			0x00000001
+#define I2C_FUNC_10BIT_ADDR		0x00000002
+#define I2C_FUNC_PROTOCOL_MANGLING	0x00000004 /* I2C_M_{REV_DIR_ADDR,NOSTART,..} */
+#define I2C_FUNC_SMBUS_HWPEC_CALC	0x00000008 /* SMBus 2.0 */
+#define I2C_FUNC_SMBUS_READ_WORD_DATA_PEC  0x00000800 /* SMBus 2.0 */
+#define I2C_FUNC_SMBUS_WRITE_WORD_DATA_PEC 0x00001000 /* SMBus 2.0 */
+#define I2C_FUNC_SMBUS_PROC_CALL_PEC	0x00002000 /* SMBus 2.0 */
+#define I2C_FUNC_SMBUS_BLOCK_PROC_CALL_PEC 0x00004000 /* SMBus 2.0 */
+#define I2C_FUNC_SMBUS_BLOCK_PROC_CALL	0x00008000 /* SMBus 2.0 */
+#define I2C_FUNC_SMBUS_QUICK		0x00010000
+#define I2C_FUNC_SMBUS_READ_BYTE	0x00020000
+#define I2C_FUNC_SMBUS_WRITE_BYTE	0x00040000
+#define I2C_FUNC_SMBUS_READ_BYTE_DATA	0x00080000
+#define I2C_FUNC_SMBUS_WRITE_BYTE_DATA	0x00100000
+#define I2C_FUNC_SMBUS_READ_WORD_DATA	0x00200000
+#define I2C_FUNC_SMBUS_WRITE_WORD_DATA	0x00400000
+#define I2C_FUNC_SMBUS_PROC_CALL	0x00800000
+#define I2C_FUNC_SMBUS_READ_BLOCK_DATA	0x01000000
+#define I2C_FUNC_SMBUS_WRITE_BLOCK_DATA 0x02000000
+#define I2C_FUNC_SMBUS_READ_I2C_BLOCK	0x04000000 /* I2C-like block xfer  */
+#define I2C_FUNC_SMBUS_WRITE_I2C_BLOCK	0x08000000 /* w/ 1-byte reg. addr. */
+#define I2C_FUNC_SMBUS_READ_I2C_BLOCK_2	 0x10000000 /* I2C-like block xfer  */
+#define I2C_FUNC_SMBUS_WRITE_I2C_BLOCK_2 0x20000000 /* w/ 2-byte reg. addr. */
+#define I2C_FUNC_SMBUS_READ_BLOCK_DATA_PEC  0x40000000 /* SMBus 2.0 */
+#define I2C_FUNC_SMBUS_WRITE_BLOCK_DATA_PEC 0x80000000 /* SMBus 2.0 */
+
+#define I2C_FUNC_SMBUS_BYTE I2C_FUNC_SMBUS_READ_BYTE | \
+                            I2C_FUNC_SMBUS_WRITE_BYTE
+#define I2C_FUNC_SMBUS_BYTE_DATA I2C_FUNC_SMBUS_READ_BYTE_DATA | \
+                                 I2C_FUNC_SMBUS_WRITE_BYTE_DATA
+#define I2C_FUNC_SMBUS_WORD_DATA I2C_FUNC_SMBUS_READ_WORD_DATA | \
+                                 I2C_FUNC_SMBUS_WRITE_WORD_DATA
+#define I2C_FUNC_SMBUS_BLOCK_DATA I2C_FUNC_SMBUS_READ_BLOCK_DATA | \
+                                  I2C_FUNC_SMBUS_WRITE_BLOCK_DATA
+#define I2C_FUNC_SMBUS_I2C_BLOCK I2C_FUNC_SMBUS_READ_I2C_BLOCK | \
+                                  I2C_FUNC_SMBUS_WRITE_I2C_BLOCK
+#define I2C_FUNC_SMBUS_I2C_BLOCK_2 I2C_FUNC_SMBUS_READ_I2C_BLOCK_2 | \
+                                   I2C_FUNC_SMBUS_WRITE_I2C_BLOCK_2
+#define I2C_FUNC_SMBUS_BLOCK_DATA_PEC I2C_FUNC_SMBUS_READ_BLOCK_DATA_PEC | \
+                                      I2C_FUNC_SMBUS_WRITE_BLOCK_DATA_PEC
+#define I2C_FUNC_SMBUS_WORD_DATA_PEC  I2C_FUNC_SMBUS_READ_WORD_DATA_PEC | \
+                                      I2C_FUNC_SMBUS_WRITE_WORD_DATA_PEC
+
+#define I2C_FUNC_SMBUS_READ_BYTE_PEC		I2C_FUNC_SMBUS_READ_BYTE_DATA
+#define I2C_FUNC_SMBUS_WRITE_BYTE_PEC		I2C_FUNC_SMBUS_WRITE_BYTE_DATA
+#define I2C_FUNC_SMBUS_READ_BYTE_DATA_PEC	I2C_FUNC_SMBUS_READ_WORD_DATA
+#define I2C_FUNC_SMBUS_WRITE_BYTE_DATA_PEC	I2C_FUNC_SMBUS_WRITE_WORD_DATA
+#define I2C_FUNC_SMBUS_BYTE_PEC			I2C_FUNC_SMBUS_BYTE_DATA
+#define I2C_FUNC_SMBUS_BYTE_DATA_PEC		I2C_FUNC_SMBUS_WORD_DATA
+
+#define I2C_FUNC_SMBUS_EMUL I2C_FUNC_SMBUS_QUICK | \
+                            I2C_FUNC_SMBUS_BYTE | \
+                            I2C_FUNC_SMBUS_BYTE_DATA | \
+                            I2C_FUNC_SMBUS_WORD_DATA | \
+                            I2C_FUNC_SMBUS_PROC_CALL | \
+                            I2C_FUNC_SMBUS_WRITE_BLOCK_DATA | \
+                            I2C_FUNC_SMBUS_WRITE_BLOCK_DATA_PEC | \
+                            I2C_FUNC_SMBUS_I2C_BLOCK
+
+/*
+ * Data for SMBus Messages
+ */
+#define I2C_SMBUS_BLOCK_MAX	32	/* As specified in SMBus standard */
+#define I2C_SMBUS_I2C_BLOCK_MAX	32	/* Not specified but we use same structure */
+union i2c_smbus_data {
+	__u8 byte;
+	__u16 word;
+	__u8 block[I2C_SMBUS_BLOCK_MAX + 3]; /* block[0] is used for length */
+                          /* one more for read length in block process call */
+	                                            /* and one more for PEC */
+};
+
+/* smbus_access read or write markers */
+#define I2C_SMBUS_READ	1
+#define I2C_SMBUS_WRITE	0
+
+/* SMBus transaction types (size parameter in the above functions)
+   Note: these no longer correspond to the (arbitrary) PIIX4 internal codes! */
+#define I2C_SMBUS_QUICK		    0
+#define I2C_SMBUS_BYTE		    1
+#define I2C_SMBUS_BYTE_DATA	    2
+#define I2C_SMBUS_WORD_DATA	    3
+#define I2C_SMBUS_PROC_CALL	    4
+#define I2C_SMBUS_BLOCK_DATA	    5
+#define I2C_SMBUS_I2C_BLOCK_DATA    6
+#define I2C_SMBUS_BLOCK_PROC_CALL   7		/* SMBus 2.0 */
+#define I2C_SMBUS_BLOCK_DATA_PEC    8		/* SMBus 2.0 */
+#define I2C_SMBUS_PROC_CALL_PEC     9		/* SMBus 2.0 */
+#define I2C_SMBUS_BLOCK_PROC_CALL_PEC  10	/* SMBus 2.0 */
+#define I2C_SMBUS_WORD_DATA_PEC	   11		/* SMBus 2.0 */
+
+
+/* ----- commands for the ioctl like i2c_command call:
+ * note that additional calls are defined in the algorithm and hw
+ *	dependent layers - these can be listed here, or see the
+ *	corresponding header files.
+ */
+				/* -> bit-adapter specific ioctls	*/
+#define I2C_RETRIES	0x0701	/* number of times a device address      */
+				/* should be polled when not            */
+                                /* acknowledging 			*/
+#define I2C_TIMEOUT	0x0702	/* set timeout - call with int 		*/
+
+
+/* this is for i2c-dev.c	*/
+#define I2C_SLAVE	0x0703	/* Change slave address			*/
+				/* Attn.: Slave address is 7 or 10 bits */
+#define I2C_SLAVE_FORCE	0x0706	/* Change slave address			*/
+				/* Attn.: Slave address is 7 or 10 bits */
+				/* This changes the address, even if it */
+				/* is already taken!			*/
+#define I2C_TENBIT	0x0704	/* 0 for 7 bit addrs, != 0 for 10 bit	*/
+
+#define I2C_FUNCS	0x0705	/* Get the adapter functionality */
+#define I2C_RDWR	0x0707	/* Combined R/W transfer (one stop only)*/
+#define I2C_PEC		0x0708	/* != 0 for SMBus PEC                   */
+#if 0
+#define I2C_ACK_TEST	0x0710	/* See if a slave is at a specific address */
+#endif
+
+#define I2C_SMBUS	0x0720	/* SMBus-level access */
+
+/* ... algo-bit.c recognizes */
+#define I2C_UDELAY	0x0705	/* set delay in microsecs between each	*/
+				/* written byte (except address)	*/
+#define I2C_MDELAY	0x0706	/* millisec delay between written bytes */
+
+/* -- i2c.h -- */
+
+
+/* Note: 10-bit addresses are NOT supported! */
+
+/* This is the structure as used in the I2C_SMBUS ioctl call */
+struct i2c_smbus_ioctl_data {
+	__u8 read_write;
+	__u8 command;
+	__u32 size;
+	union i2c_smbus_data __user *data;
+};
+
+/* This is the structure as used in the I2C_RDWR ioctl call */
+struct i2c_rdwr_ioctl_data {
+	struct i2c_msg __user *msgs;	/* pointers to i2c_msgs */
+	__u32 nmsgs;			/* number of i2c_msgs */
+};
+
+static inline __s32 i2c_smbus_access(int file, __u8 read_write, __u8 command, 
+                                     __u32 size, union i2c_smbus_data __user *data)
+{
+	struct i2c_smbus_ioctl_data args;
+
+	args.read_write = read_write;
+	args.command = command;
+	args.size = size;
+	args.data = data;
+	return ioctl(file,I2C_SMBUS,&args);
+}
+
+
+static inline __s32 i2c_smbus_write_quick(int file, __u8 value)
+{
+	return i2c_smbus_access(file,value,0,I2C_SMBUS_QUICK,NULL);
+}
+	
+static inline __s32 i2c_smbus_read_byte(int file)
+{
+	union i2c_smbus_data __user data;
+	if (i2c_smbus_access(file,I2C_SMBUS_READ,0,I2C_SMBUS_BYTE,&data))
+		return -1;
+	else
+		return 0x0FF & data.byte;
+}
+
+static inline __s32 i2c_smbus_write_byte(int file, __u8 value)
+{
+	return i2c_smbus_access(file,I2C_SMBUS_WRITE,value,
+	                        I2C_SMBUS_BYTE,NULL);
+}
+
+static inline __s32 i2c_smbus_read_byte_data(int file, __u8 command)
+{
+	union i2c_smbus_data __user data;
+	if (i2c_smbus_access(file,I2C_SMBUS_READ,command,
+	                     I2C_SMBUS_BYTE_DATA,&data))
+		return -1;
+	else
+		return 0x0FF & data.byte;
+}
+
+static inline __s32 i2c_smbus_write_byte_data(int file, __u8 command, 
+                                              __u8 value)
+{
+	union i2c_smbus_data __user data;
+	data.byte = value;
+	return i2c_smbus_access(file,I2C_SMBUS_WRITE,command,
+	                        I2C_SMBUS_BYTE_DATA, &data);
+}
+
+static inline __s32 i2c_smbus_read_word_data(int file, __u8 command)
+{
+	union i2c_smbus_data __user data;
+	if (i2c_smbus_access(file,I2C_SMBUS_READ,command,
+	                     I2C_SMBUS_WORD_DATA,&data))
+		return -1;
+	else
+		return 0x0FFFF & data.word;
+}
+
+static inline __s32 i2c_smbus_write_word_data(int file, __u8 command, 
+                                              __u16 value)
+{
+	union i2c_smbus_data __user data;
+	data.word = value;
+	return i2c_smbus_access(file,I2C_SMBUS_WRITE,command,
+	                        I2C_SMBUS_WORD_DATA, &data);
+}
+
+static inline __s32 i2c_smbus_process_call(int file, __u8 command, __u16 value)
+{
+	union i2c_smbus_data __user data;
+	data.word = value;
+	if (i2c_smbus_access(file,I2C_SMBUS_WRITE,command,
+	                     I2C_SMBUS_PROC_CALL,&data))
+		return -1;
+	else
+		return 0x0FFFF & data.word;
+}
+
+
+/* Returns the number of read bytes */
+static inline __s32 i2c_smbus_read_block_data(int file, __u8 command, 
+                                              __u8 *values)
+{
+	union i2c_smbus_data __user data;
+	int i;
+	if (i2c_smbus_access(file,I2C_SMBUS_READ,command,
+	                     I2C_SMBUS_BLOCK_DATA,&data))
+		return -1;
+	else {
+		for (i = 1; i <= data.block[0]; i++)
+			values[i-1] = data.block[i];
+		return data.block[0];
+	}
+}
+
+static inline __s32 i2c_smbus_write_block_data(int file, __u8 command, 
+                                               __u8 length, __u8 *values)
+{
+	union i2c_smbus_data __user data;
+	int i;
+	if (length > 32)
+		length = 32;
+	for (i = 1; i <= length; i++)
+		data.block[i] = values[i-1];
+	data.block[0] = length;
+	return i2c_smbus_access(file,I2C_SMBUS_WRITE,command,
+	                        I2C_SMBUS_BLOCK_DATA, &data);
+}
+
+/* Returns the number of read bytes */
+static inline __s32 i2c_smbus_read_i2c_block_data(int file, __u8 command,
+                                                  __u8 *values)
+{
+	union i2c_smbus_data __user data;
+	int i;
+	if (i2c_smbus_access(file,I2C_SMBUS_READ,command,
+	                      I2C_SMBUS_I2C_BLOCK_DATA,&data))
+		return -1;
+	else {
+		for (i = 1; i <= data.block[0]; i++)
+			values[i-1] = data.block[i];
+		return data.block[0];
+	}
+}
+
+static inline __s32 i2c_smbus_write_i2c_block_data(int file, __u8 command,
+                                               __u8 length, __u8 *values)
+{
+	union i2c_smbus_data __user data;
+	int i;
+	if (length > 32)
+		length = 32;
+	for (i = 1; i <= length; i++)
+		data.block[i] = values[i-1];
+	data.block[0] = length;
+	return i2c_smbus_access(file,I2C_SMBUS_WRITE,command,
+	                        I2C_SMBUS_I2C_BLOCK_DATA, &data);
+}
+
+/* Returns the number of read bytes */
+static inline __s32 i2c_smbus_block_process_call(int file, __u8 command,
+                                                 __u8 length, __u8 *values)
+{
+	union i2c_smbus_data __user data;
+	int i;
+	if (length > 32)
+		length = 32;
+	for (i = 1; i <= length; i++)
+		data.block[i] = values[i-1];
+	data.block[0] = length;
+	if (i2c_smbus_access(file,I2C_SMBUS_WRITE,command,
+	                     I2C_SMBUS_BLOCK_PROC_CALL,&data))
+		return -1;
+	else {
+		for (i = 1; i <= data.block[0]; i++)
+			values[i-1] = data.block[i];
+		return data.block[0];
+	}
+}
+
+#endif /* __KERNEL__ */
+
 #endif /* _LINUX_I2C_DEV_H */
--- linux-2.6.9/include/linux/i2c-id.h	2004-10-18 23:53:10.000000000 +0200
+++ linux-2.6.9.axxmetro/include/linux/i2c-id.h	2004-11-11 17:28:03.000000000 +0100
@@ -195,6 +195,7 @@
 #define I2C_ALGO_BITHS	0x130000	/* enhanced bit style adapters	*/
 #define I2C_ALGO_OCP_IOP3XX  0x140000	/* XSCALE IOP3XX On-chip I2C alg */
 #define I2C_ALGO_PCA	0x150000	/* PCA 9564 style adapters	*/
+#define I2C_ALGO_MPC8260 0x160000       /* MPC8260 PowerPC I2C algorithm */
 
 #define I2C_ALGO_EXP	0x800000	/* experimental			*/
 
@@ -252,6 +253,10 @@
 /* --- MPC8xx PowerPC adapters						*/
 #define I2C_HW_MPC8XX_EPON 0x00	/* Eponymous MPC8xx I2C adapter 	*/
 
+/* --- MPC8260 PowerPC adapters                                         */
+#define I2C_HW_MPC8260_PM826    0x00    /* PM826    MPC8260 I2C adapter */
+#define I2C_HW_MPC8260_CPU86    0x01    /* CPU86    MPC8260 I2C adapter */
+
 /* --- ITE based algorithms						*/
 #define I2C_HW_I_IIC	0x00	/* controller on the ITE */
 

^ permalink raw reply	[flat|nested] 2+ messages in thread

* MPC85xx OCP->platform patches
  2004-11-16  8:06 MPC8260 I2C miguel.valero
@ 2004-11-17 15:32 ` McMullan, Jason
  0 siblings, 0 replies; 2+ messages in thread
From: McMullan, Jason @ 2004-11-17 15:32 UTC (permalink / raw)
  To: linuxppc-embedded

On Tue, 2004-11-16 at 09:06 +0100, miguel.valero@axxessit.no wrote:
> Probably, but the OCP or platform_device work is something that needs =
to
> get at some point.  I'll take a look, if you're willing to push the
> driver with upstream I2C folks.

I have OCP->platform patches for 2.6.9 at
http://67.171.103.33/~gus/patches

They'll be moving to their permanent location at
http://www.evillabs.net/~gus/patches in a few hours.

These patches are currently being reviewed, so they may change at any
time without notice.


--=20
Jason McMullan <jason.mcmullan@timesys.com>

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2004-11-17 15:51 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2004-11-16  8:06 MPC8260 I2C miguel.valero
2004-11-17 15:32 ` MPC85xx OCP->platform patches McMullan, Jason

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).