* 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).