Skip to contentSkip to conversation

i2c: adds support for i2c bus on 8xx

PATCH In review Jochen Friedrich 3 participants 6 messages Oct 15, 2007 – Oct 23, 2007

Subsystems (4)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 i2c: adds support for i2c bus on 8xx

Using the port of 2.4 code from Vitaly Bordug <[email protected]> and the actual algorithm used by the i2c driver of the DBox code on cvs.tuxboc.org from Tmbinc, Gillem ([email protected]). Renamed i2c-algo-8xx.c to i2c-algo-cpm.c and i2c-rpx.c to i2c-8xx.c. Added original i2c-rpx.c as i2c-8xx-ppc.c for pre-OF (arch ppc) devices.

---

This can be pulled from git://git.bocc.de/dbox2.git i2c

arch/powerpc/boot/dts/mpc885ads.dts          |    9 +
arch/powerpc/platforms/8xx/mpc885ads_setup.c |    6 +
arch/powerpc/sysdev/fsl_soc.c                |   61 +++-
drivers/i2c/algos/Kconfig                    |   12 +
drivers/i2c/algos/Makefile                   |    1 +
drivers/i2c/algos/i2c-algo-cpm.c             |  563 ++++++++++++++++++++++++++
drivers/i2c/busses/Kconfig                   |   22 +
drivers/i2c/busses/Makefile                  |    2 +
drivers/i2c/busses/i2c-8xx-ppc.c             |  105 +++++
drivers/i2c/busses/i2c-8xx.c                 |  170 ++++++++
include/linux/i2c-algo-cpm.h                 |   34 ++
11 files changed, 984 insertions(+), 1 deletions(-)

create mode 100644 drivers/i2c/algos/i2c-algo-cpm.c create mode 100644 drivers/i2c/busses/i2c-8xx-ppc.c create mode 100644 drivers/i2c/busses/i2c-8xx.c create mode 100644 include/linux/i2c-algo-cpm.h

arch/powerpc/boot/dts/mpc885ads.dts +9 -0
index 8848e63..a526c02 100644
@@ -213,6 +213,15 @@
 				fsl,cpm-command = <0080>;
 				linux,network-index = <2>;
 			};
+
+			i2c@860 {
+				device_type = "i2c";
+				compatible = "fsl-i2c-cpm";
+				reg = <860 20 3c80 30>;
+				interrupts = <10>;
+				interrupt-parent = <&CPM_PIC>;
+				fsl,cpm-command = <0010>;
+			};
 		};
 	};
 
arch/powerpc/platforms/8xx/mpc885ads_setup.c +6 -0
index 2cf1b6a..350018b 100644
@@ -175,6 +175,12 @@ static void __init init_ioports(void)
 
 	/* Set FEC1 and FEC2 to MII mode */
 	clrbits32(&mpc8xx_immr->im_cpm.cp_cptr, 0x00000180);
+
+#ifdef CONFIG_I2C_8XX
+	setbits32(&mpc8xx_immr->im_cpm.cp_pbpar, 0x00000030);
+	setbits32(&mpc8xx_immr->im_cpm.cp_pbdir, 0x00000030);
+	setbits16(&mpc8xx_immr->im_cpm.cp_pbodr, 0x0030);
+#endif
 }
 
 static void __init mpc885ads_setup_arch(void)
arch/powerpc/sysdev/fsl_soc.c +60 -1

79 lines not on this page · raw message

drivers/i2c/algos/Kconfig +12 -0
index 014dfa5..7a8200e 100644
@@ -14,6 +14,18 @@ config I2C_ALGOBIT
 	  This support is also available as a module.  If so, the module 
 	  will be called i2c-algo-bit.
 
+config I2C_ALGOCPM
+	tristate "I2C MPC8xx CPM and MPC8260 CPM2 interfaces"
+	depends on ( 8xx || 8260 ) && I2C
+	help
+	  CPM I2C Algorithm, supports the CPM I2C interface for mpc8xx
+	  and mpc8260 CPUs. Say Y if you own a CPU of this class and wish
+	  to use the I2C interface and say Y to the specific driver for the
+	  particular CPU.
+
+	  This support is also available as a module.  If so, the module
+	  will be called i2c-algo-cpm.
+
 config I2C_ALGOPCF
 	tristate "I2C PCF 8584 interfaces"
 	help
drivers/i2c/algos/Makefile +1 -0
index cac1051..b5fe28c 100644
@@ -6,6 +6,7 @@ obj-$(CONFIG_I2C_ALGOBIT)	+= i2c-algo-bit.o
 obj-$(CONFIG_I2C_ALGOPCF)	+= i2c-algo-pcf.o
 obj-$(CONFIG_I2C_ALGOPCA)	+= i2c-algo-pca.o
 obj-$(CONFIG_I2C_ALGO_SGI)	+= i2c-algo-sgi.o
+obj-$(CONFIG_I2C_ALGOCPM)	+= i2c-algo-cpm.o
 
 ifeq ($(CONFIG_I2C_DEBUG_ALGO),y)
 EXTRA_CFLAGS += -DDEBUG
drivers/i2c/algos/i2c-algo-cpm.c new file +563 -0

563 lines not on this page · raw message

drivers/i2c/busses/Kconfig +22 -0
index de95c75..705997b 100644
@@ -4,6 +4,28 @@
 
 menu "I2C Hardware Bus support"
 
+config I2C_8XX_PPC
+	tristate "MPC8xx CPM oldstyle (no OF)"
+	depends on 8xx && I2C && !OF
+	select I2C_ALGOCPM
+	help
+	  This supports the use of the I2C interface on Freescale MPC8xx
+	  processors.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called i2c-8xx-ppc.
+
+config I2C_8XX
+	tristate "MPC8xx CPM with Open Firmware"
+	depends on 8xx && I2C && OF
+	select I2C_ALGOCPM
+	help
+	  This supports the use of the I2C interface on Freescale MPC8xx
+	  processors.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called i2c-8xx.
+
 config I2C_ALI1535
 	tristate "ALI 1535"
 	depends on PCI
drivers/i2c/busses/Makefile +2 -0
index 81d43c2..f2feb4b 100644
@@ -2,6 +2,8 @@
 # Makefile for the i2c bus drivers.
 #
 
+obj-$(CONFIG_I2C_8XX_PPC)	+= i2c-8xx-ppc.o
+obj-$(CONFIG_I2C_8XX)		+= i2c-8xx.o
 obj-$(CONFIG_I2C_ALI1535)	+= i2c-ali1535.o
 obj-$(CONFIG_I2C_ALI1563)	+= i2c-ali1563.o
 obj-$(CONFIG_I2C_ALI15X3)	+= i2c-ali15x3.o
drivers/i2c/busses/i2c-8xx-ppc.c new file +105 -0

105 lines not on this page · raw message

drivers/i2c/busses/i2c-8xx.c new file +170 -0

170 lines not on this page · raw message

include/linux/i2c-algo-cpm.h new file +34 -0
new file mode 100644
index 0000000..2192b7d
@@ -0,0 +1,34 @@
+/* ------------------------------------------------------------------------- */
+/* i2c-algo-cpm.h i2c driver algorithms for MPX8XX CPM or MPC8250 CPM2       */
+/* ------------------------------------------------------------------------- */
+
+#ifndef I2C_ALGO_CPM_H
+#define I2C_ALGO_CPM_H
+
+#include <linux/i2c.h>
+#include <asm/8xx_immap.h>
+#include <asm/commproc.h>
+
+#define CPM_MAX_READ    513
+#define CPM_MAXBD       4
+
+struct i2c_algo_cpm_data {
+	uint dp_addr;
+	int reloc;
+	int irq;
+	i2c8xx_t *i2c;
+	iic_t *iip;
+	cpm8xx_t *cp;
+	wait_queue_head_t iic_wait;
+	struct mutex iic_mutex; /* Protects I2C CPM */
+	u_char *txbuf[CPM_MAXBD];
+	u_char *rxbuf[CPM_MAXBD];
+	u32 txdma[CPM_MAXBD];
+	u32 rxdma[CPM_MAXBD];
+};
+
+extern int i2c_cpm_add_bus(struct i2c_adapter *);
+extern int i2c_cpm_del_bus(struct i2c_adapter *);
+
+#endif /* I2C_ALGO_CPM_H */
+
#1 lore raw
Quoted 5 lines · Jochen Friedrich

Using the port of 2.4 code from Vitaly Bordug <[email protected]> and the actual algorithm used by the i2c driver of the DBox code on cvs.tuxboc.org from Tmbinc, Gillem ([email protected]). Renamed i2c-algo-8xx.c to i2c-algo-cpm.c and i2c-rpx.c to i2c-8xx.c. Added original i2c-rpx.c as i2c-8xx-ppc.c for pre-OF (arch ppc) devices.

Do we really need to be adding features for arch/ppc at this point? It'll be going away in June. arch/ppc-specific things outside of arch/ppc itself will also be more likely to be missed in the removal.

Also, please post inline rather than as an attachment; attachments are harder to quote in a reply.

arch/powerpc/boot/dts/mpc885ads.dts line 218

Quoted 11 lines
arch/powerpc/boot/dts/mpc885ads.dts +3 -0
index 8848e63..a526c02 100644
@@ -213,6 +213,15 @@
 				fsl,cpm-command = <0080>;
 				linux,network-index = <2>;
 			};
+
+			i2c@860 {
+				device_type = "i2c";

No device_type.

arch/powerpc/boot/dts/mpc885ads.dts line 219

Quoted 1 line
arch/powerpc/boot/dts/mpc885ads.dts +1 -0
+				compatible = "fsl-i2c-cpm";

Should be fsl,cpm-i2c. Is cpm2 i2c the same? If not, it should be fsl,cpm1-i2c. It's probably best to specify it anyway, along with fsl,mpc885-i2c.

Quoted 5 lines
arch/powerpc/platforms/8xx/mpc885ads_setup.c +0 -0
index 2cf1b6a..350018b 100644

arch/powerpc/platforms/8xx/mpc885ads_setup.c static void __init init_ioports(void) · line 183

Quoted 9 lines
arch/powerpc/platforms/8xx/mpc885ads_setup.c +6 -0
@@ -175,6 +175,12 @@ static void __init init_ioports(void)
 
 	/* Set FEC1 and FEC2 to MII mode */
 	clrbits32(&mpc8xx_immr->im_cpm.cp_cptr, 0x00000180);
+
+#ifdef CONFIG_I2C_8XX
+	setbits32(&mpc8xx_immr->im_cpm.cp_pbpar, 0x00000030);
+	setbits32(&mpc8xx_immr->im_cpm.cp_pbdir, 0x00000030);
+	setbits16(&mpc8xx_immr->im_cpm.cp_pbodr, 0x0030);
+#endif

Please add this to mpc885ads_pins, rather than poking the registers directly. The relevant lines are:

	{CPM_PORTB, 26, CPM_PIN_OUTPUT},
	{CPM_PORTB, 27, CPM_PIN_OUTPUT},
Quoted 4 lines
arch/powerpc/platforms/8xx/mpc885ads_setup.c +4 -0
+static const char *i2c_regs = "regs";
+static const char *i2c_pram = "pram";
+static const char *i2c_irq = "interrupt";
+

arch/powerpc/platforms/8xx/mpc885ads_setup.c static void __init init_ioports(void)

Quoted 10 lines
arch/powerpc/platforms/8xx/mpc885ads_setup.c +10 -0
+static int __init fsl_i2c_cpm_of_init(void)
+{
+	struct device_node *np;
+	unsigned int i;
+	struct platform_device *i2c_dev;
+	int ret;
+
+	for (np = NULL, i = 0;
+	     (np = of_find_compatible_node(np, "i2c", "fsl-i2c-cpm")) != NULL;
+	     i++) {

Why not just make an of_platform device instead of this glue code?

Quoted 5 lines
drivers/i2c/algos/Kconfig +0 -0
index 014dfa5..7a8200e 100644

drivers/i2c/algos/Kconfig config I2C_ALGOBIT · line 22

Quoted 9 lines
drivers/i2c/algos/Kconfig +6 -0
@@ -14,6 +14,18 @@ config I2C_ALGOBIT
 	  This support is also available as a module.  If so, the module 
 	  will be called i2c-algo-bit.
 
+config I2C_ALGOCPM
+	tristate "I2C MPC8xx CPM and MPC8260 CPM2 interfaces"
+	depends on ( 8xx || 8260 ) && I2C
+	help
+	  CPM I2C Algorithm, supports the CPM I2C interface for mpc8xx
+	  and mpc8260 CPUs. Say Y if you own a CPU of this class 

What if I'm just borrowing it? :-)

Quoted 15 lines
drivers/i2c/algos/Kconfig +15 -0
+static irqreturn_t cpm_iic_interrupt(int irq, void *dev_id)
+{
+	struct i2c_adapter *adap;
+	struct i2c_algo_cpm_data *cpm;
+	i2c8xx_t *i2c;
+	int i;
+
+	adap = (struct i2c_adapter *) dev_id;
+	cpm = adap->algo_data;
+	i2c = cpm->i2c;
+
+	/* Clear interrupt.
+	 */
+	i = in_8(&i2c->i2c_i2cer);
+	out_8(&i2c->i2c_i2cer, i);

drivers/i2c/algos/Kconfig config I2C_ALGOBIT

Quoted 10 lines
drivers/i2c/algos/Kconfig +10 -0
+
+	if (cpm_debug)
+		dev_dbg(&adap->dev, "Interrupt: %x\n", i);
+
+	/* Get 'me going again.
+	 */
+	wake_up_interruptible(&cpm->iic_wait);
+
+	return IRQ_HANDLED;
+}

Should only return IRQ_HANDLED if the event register was non-zero.

drivers/i2c/algos/Kconfig

Quoted 10 lines
drivers/i2c/algos/Kconfig +10 -0
+static int cpm_iic_init(struct i2c_adapter *adap)
+{
+	struct i2c_algo_cpm_data *cpm = adap->algo_data;
+	iic_t *iip = cpm->iip;
+	i2c8xx_t *i2c = cpm->i2c;
+	unsigned char brg;
+	int ret, i;
+
+	if (cpm_debug)
+		dev_dbg(&adap->dev, "cpm_iic_init()\n");

Can you fold the if statement into a macro? Or just do a raw dev_dbg with no test, like most drivers do.

Quoted 7 lines
drivers/i2c/algos/Kconfig +7 -0
+	ret = 0;
+	init_waitqueue_head(&cpm->iic_wait);
+	mutex_init(&cpm->iic_mutex);
+	/* Initialize the parameter ram.
+	 * We need to make sure many things are initialized to zero,
+	 * especially in the case of a microcode patch.
+	 */

drivers/i2c/algos/Kconfig

Quoted 10 lines
drivers/i2c/algos/Kconfig +10 -0
+	out_be32(&iip->iic_rstate, 0);
+	out_be32(&iip->iic_rdp, 0);
+	out_be16(&iip->iic_rbptr, 0);
+	out_be16(&iip->iic_rbc, 0);
+	out_be32(&iip->iic_rxtmp, 0);
+	out_be32(&iip->iic_tstate, 0);
+	out_be32(&iip->iic_tdp, 0);
+	out_be16(&iip->iic_tbptr, 0);
+	out_be16(&iip->iic_tbc, 0);
+	out_be32(&iip->iic_txtmp, 0);

This appears to be done twice, here and in cpm_reset_iic_params.

drivers/i2c/algos/Kconfig

Quoted 1 line
drivers/i2c/algos/Kconfig +1 -0
+		u16 v = mk_cr_cmd(CPM_CR_CH_I2C, CPM_CR_INIT_TRX) | CPM_CR_FLG;

Should use fsl,cpm-command rather than hardcoded constants.

drivers/i2c/algos/Kconfig

Quoted 3 lines
drivers/i2c/algos/Kconfig +3 -0
+	/* Select an arbitrary address.  Just make sure it is unique.
+	 */
+	out_8(&i2c->i2c_i2add, 0xfe);

It's a 7-bit address... and are you sure that 0x7e is unique? Does this driver even support slave operation?

drivers/i2c/algos/Kconfig

Quoted 5 lines
drivers/i2c/algos/Kconfig +5 -0
+	/* Make clock run at 60 kHz.
+	 */
+	/* brg = ppc_proc_freq / (32 * 2 * 60000) - 3; */
+	brg = 7;
+	out_8(&i2c->i2c_i2brg, brg);

Why is this hardcoded?

Quoted 17 lines
drivers/i2c/algos/Kconfig +17 -0
+	out_8(&i2c->i2c_i2mod, 0x00);
+	out_8(&i2c->i2c_i2com, 0x01);	/* Master mode */
+
+	/* Disable interrupts.
+	 */
+	out_8(&i2c->i2c_i2cmr, 0);
+	out_8(&i2c->i2c_i2cer, 0xff);
+
+	/* Allocate TX and RX buffers */
+	for (i = 0; i < CPM_MAXBD; i++) {
+		cpm->rxbuf[i] = (unsigned char *)dma_alloc_coherent(
+			NULL, CPM_MAX_READ + 1, &cpm->rxdma[i], GFP_KERNEL);
+		if (!cpm->rxbuf[i]) {
+			ret = -ENOMEM;
+			goto out;
+		}
+		cpm->txbuf[i] = (unsigned char *)dma_alloc_coherent(

drivers/i2c/algos/Kconfig

Quoted 10 lines
drivers/i2c/algos/Kconfig +10 -0
+			NULL, CPM_MAX_READ + 1, &cpm->txdma[i], GFP_KERNEL);
+		if (!cpm->txbuf[i]) {
+			ret = -ENOMEM;
+			goto out;
+		}
+	}
+
+	/* Install interrupt handler.
+	 */
+	if (request_irq(cpm->irq, cpm_iic_interrupt, 0, "8xx_i2c", adap)) {

cpm-i2c, not 8xx.

drivers/i2c/algos/Kconfig

Quoted 12 lines
drivers/i2c/algos/Kconfig +12 -0
+		ret = -EIO;
+		goto out;
+	}
+
+	return 0;
+out:
+	for (i = 0; i < CPM_MAXBD; i++) {
+		if (cpm->rxbuf[i]) dma_free_coherent(NULL, CPM_MAX_READ + 1,
+			cpm->rxbuf[i], cpm->rxdma[i]);
+		if (cpm->txbuf[i]) dma_free_coherent(NULL, CPM_MAX_READ + 1,
+			cpm->txbuf[i], cpm->txdma[i]);
+	}

Please put a newline between the if test and the if body.

drivers/i2c/algos/Kconfig

Quoted 8 lines
drivers/i2c/algos/Kconfig +8 -0
+static void force_close(struct i2c_adapter *adap)
+{
+	struct i2c_algo_cpm_data *cpm = adap->algo_data;
+	i2c8xx_t *i2c = cpm->i2c;
+	if (cpm->reloc == 0) {	/* micro code disabled */
+		cpm8xx_t *cp = cpm->cp;
+		u16 v =
+		    mk_cr_cmd(CPM_CR_CH_I2C, CPM_CR_CLOSE_RXBD) | CPM_CR_FLG;

Why only if there's no microcode relocation?

Quoted 5 lines
drivers/i2c/algos/Kconfig +5 -0
+static void cpm_parse_message(struct i2c_adapter *adap, struct i2c_msg *pmsg,
+	int num, int tx, int rx)
+{
+	cbd_t *tbdf, *rbdf;
+	u_char addr;

drivers/i2c/algos/Kconfig

Quoted 10 lines
drivers/i2c/algos/Kconfig +10 -0
+	u_char *tb;
+	u_char *rb;
+	struct i2c_algo_cpm_data *cpm = adap->algo_data;
+	iic_t *iip = cpm->iip;
+	int i, dscan;
+
+	tbdf = (cbd_t *) cpm_dpram_addr(in_be16(&iip->iic_tbase));
+	rbdf = (cbd_t *) cpm_dpram_addr(in_be16(&iip->iic_rbase));
+
+	/* This chip can't do zero lenth writes. However, the i2c core uses

s/lenth/length/

drivers/i2c/algos/Kconfig

Quoted 11 lines
drivers/i2c/algos/Kconfig +11 -0
+	if (pmsg->flags & I2C_M_RD) {
+		if (cpm_debug)
+			dev_dbg(&adap->dev, "rx sc %04x, rx sc %04x\n",
+				tbdf[tx].cbd_sc, rbdf[rx].cbd_sc);
+		if (tbdf[tx].cbd_sc & BD_SC_NAK) {
+			if (cpm_debug)
+				dev_dbg(&adap->dev, "IIC read; no ack\n");
+			if (pmsg->flags & I2C_M_IGNORE_NAK)
+				return 0;
+			else
+				return -EREMOTEIO;

s/EREMOTEIO/EIO/

Quoted 10 lines
drivers/i2c/algos/Kconfig +10 -0
+static int cpm_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+{
+	struct i2c_algo_cpm_data *cpm = adap->algo_data;
+	i2c8xx_t *i2c = cpm->i2c;
+	iic_t *iip = cpm->iip;
+	struct i2c_msg *pmsg, *rmsg;
+	int ret, i;
+	int tptr;
+	int rptr;
+	cbd_t *tbdf, *rbdf;

drivers/i2c/algos/Kconfig

Quoted 10 lines
drivers/i2c/algos/Kconfig +10 -0
+
+	if (num > CPM_MAXBD)
+		return -EREMOTEIO;
+
+	/* Check if we have any oversized READ requests */
+	for (i = 0; i < num; i++) {
+		pmsg = &msgs[i];
+		if (pmsg->len >= CPM_MAX_READ)
+			return -EREMOTEIO;
+	}

s/EREMOTEIO/EINVAL/

drivers/i2c/algos/Kconfig

Quoted 6 lines
drivers/i2c/algos/Kconfig +6 -0
+
+	mutex_lock(&cpm->iic_mutex);
+
+	/* check for and use a microcode relocation patch */
+	if (cpm->reloc)
+		cpm_reset_iic_params(cpm);

On every transfer?

Quoted 4 lines
drivers/i2c/algos/Kconfig +4 -0
+	while (tptr < num) {
+		/* Check for outstanding messages */
+		dev_dbg(&adap->dev, "test ready.\n");
+		if (!(tbdf[tptr].cbd_sc & BD_SC_READY)) {

drivers/i2c/algos/Kconfig

Quoted 10 lines
drivers/i2c/algos/Kconfig +10 -0
+			dev_dbg(&adap->dev, "ready.\n");
+			rmsg = &msgs[tptr];
+			ret = cpm_check_message(adap, rmsg, tptr, rptr);
+			tptr++;
+			if (rmsg->flags & I2C_M_RD)
+				rptr++;
+			if (ret) {
+				force_close(adap);
+				mutex_unlock(&cpm->iic_mutex);
+				return -EREMOTEIO;

s/-EREMOTEIO/ret/

drivers/i2c/algos/Kconfig

Quoted 2 lines
drivers/i2c/algos/Kconfig +2 -0
+config I2C_8XX
+	tristate "MPC8xx CPM with Open Firmware"

It's not really Open Firmware... just a flat device tree.

Quoted 10 lines
drivers/i2c/busses/i2c-8xx.c new file +4 -0
new file mode 100644
index 0000000..c38b52e
@@ -0,0 +1,170 @@
+/*
+ * Embedded Planet RPX Lite MPC8xx CPM I2C interface.
+ * Copyright (c) 1999 Dan Malek ([email protected]).
+ *

drivers/i2c/busses/i2c-8xx.c line 14

Quoted 10 lines
drivers/i2c/busses/i2c-8xx.c new file +10 -0
+ * moved into proper i2c interface;
+ * Brad Parker ([email protected])
+ *
+ * (C) 2007 Montavista Software, Inc.
+ * Vitaly Bordug <[email protected]>
+ *
+ * RPX lite specific parts of the i2c interface
+ * Update:  There actually isn't anything RPXLite-specific about this module.
+ * This should work for most any 8xx board.  The console messages have been
+ * changed to eliminate RPXLite references.

So let's change the title at the top of the file...

drivers/i2c/busses/i2c-8xx.c line 25

Quoted 9 lines
drivers/i2c/busses/i2c-8xx.c new file +9 -0
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/stddef.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-cpm.h>
+#include <linux/of_device.h>

Why are you including platform_device, and running glue code in fsl_soc.c, if this is an of_platform driver?

Quoted 13 lines
drivers/i2c/busses/i2c-8xx.c new file +13 -0
+#include <linux/of_platform.h>
+#include <asm/mpc8xx.h>
+#include <asm/commproc.h>
+#include <asm/fs_pd.h>
+
+
+struct m8xx_i2c {
+	char *base;
+	struct of_device *ofdev;
+	struct i2c_adapter adap;
+	struct i2c_algo_cpm_data *algo_8xx;
+};
+

drivers/i2c/busses/i2c-8xx.c line 48

Quoted 10 lines
drivers/i2c/busses/i2c-8xx.c new file +10 -0
+static struct i2c_algo_cpm_data m8xx_data;
+
+static const struct i2c_adapter m8xx_ops = {
+	.owner		= THIS_MODULE,
+	.name		= "i2c-8xx",
+	.id		= I2C_HW_MPC8XX_EPON,
+	.algo_data	= &m8xx_data,
+	.dev.parent	= &platform_bus,
+	.class		= I2C_CLASS_HWMON,
+};

It's not on the platform bus; it's on the soc of_platform bus. Why is this embedded in the i2c_adapter struct anyway? i2c_adapter should hold a pointer to whatever the probe function gives you.

Quoted 11 lines
drivers/i2c/busses/i2c-8xx.c new file +11 -0
+	data->irq = irq_of_parse_and_map(np, 0);
+	if (data->irq < 0)
+		return -EINVAL;
+
+	if (of_address_to_resource(np, 1, &r))
+		return -EINVAL;
+
+	data->iip = ioremap(r.start, r.end - r.start + 1);
+	if (data->iip == NULL)
+		return -EINVAL;
+

drivers/i2c/busses/i2c-8xx.c line 83

Quoted 10 lines
drivers/i2c/busses/i2c-8xx.c new file +10 -0
+	/* Check for and use a microcode relocation patch.
+	 */
+	data->reloc = data->iip->iic_rpbase;
+	if (data->reloc)
+		data->iip = (iic_t *)&cp->cp_dpmem[data->iip->iic_rpbase];
+
+	if (of_address_to_resource(np, 0, &r))
+		return -EINVAL;
+
+	data->i2c = ioremap(r.start, r.end - r.start + 1);

Use of_iomap.

drivers/i2c/busses/i2c-8xx.c line 90

Quoted 7 lines
drivers/i2c/busses/i2c-8xx.c new file +7 -0
+	if (data->i2c == NULL)
+		return -EINVAL;
+
+	/* Allocate space for two transmit and two receive buffer
+	 * descriptors in the DP ram.
+	 */
+	data->dp_addr = cpm_dpalloc(sizeof(cbd_t) * 4, 8);

Please use the new muram_dpalloc name.

Quoted 45 lines
drivers/i2c/busses/i2c-8xx.c new file +45 -0
+	if (!data->dp_addr)
+		return -ENOMEM;
+
+	return 0;
+}
+
+static int i2c_8xx_probe(struct of_device *ofdev,
+			 const struct of_device_id *match)
+{
+	int result;
+	struct m8xx_i2c *i2c;
+
+	i2c = kzalloc(sizeof(*i2c), GFP_KERNEL);
+	if (!i2c)
+		return -ENOMEM;
+
+	i2c->ofdev = ofdev;
+	i2c->algo_8xx = &m8xx_data;
+
+	m8xx_iic_init(i2c);
+
+	dev_set_drvdata(&ofdev->dev, i2c);
+
+	i2c->adap = m8xx_ops;
+	i2c_set_adapdata(&i2c->adap, i2c);
+	i2c->adap.dev.parent = &ofdev->dev;
+
+	result = i2c_cpm_add_bus(&i2c->adap);
+	if (result < 0) {
+		printk(KERN_ERR "i2c-8xx: Unable to register with I2C\n");
+		kfree(i2c);
+	}
+
+	return result;
+}
+
+static int i2c_8xx_remove(struct of_device *ofdev)
+{
+	struct m8xx_i2c *i2c = dev_get_drvdata(&ofdev->dev);
+
+	i2c_cpm_del_bus(&i2c->adap);
+	dev_set_drvdata(&ofdev->dev, NULL);
+
+	kfree(i2c);
+	return 0;

drivers/i2c/busses/i2c-8xx.c line 145

Quoted 10 lines
drivers/i2c/busses/i2c-8xx.c new file +10 -0
+}
+
+static struct of_device_id i2c_8xx_match[] = {
+	{
+		.type = "i2c",
+		.compatible = "fsl,i2c-cpm",
+	},
+	{},
+};
+

Why is an 8xx driver matching all i2c cpm (i.e. what about cpm2)?

-Scot

#2 lore raw

Hi Scott,

Quoted 7 lines

Do we really need to be adding features for arch/ppc at this point? It'll be going away in June. arch/ppc-specific things outside of arch/ppc itself will also be more likely to be missed in the removal.

Also, please post inline rather than as an attachment; attachments are harder to quote in a reply.

OK. I'll remove the ARC=ppc parts.

Quoted 6 lines
Quoted 6 lines
arch/powerpc/boot/dts/mpc885ads.dts +0 -0
index 8848e63..a526c02 100644
@@ -213,6 +213,15 @@
 				fsl,cpm-command = <0080>;
Quoted 9 lines

arch/powerpc/boot/dts/mpc885ads.dts line 227

Quoted 6 lines
arch/powerpc/boot/dts/mpc885ads.dts +3 -0
 				linux,network-index = <2>;
 			};
+
+			i2c@860 {
+				device_type = "i2c";
 

No device_type.

Why? Documentation/powerpc/booting-without-of.txt says for I2C interfaces device_type is required and should be "i2c". Is this no longer true?

Quoted 4 lines

Should be fsl,cpm-i2c. Is cpm2 i2c the same? If not, it should be fsl,cpm1-i2c. It's probably best to specify it anyway, along with fsl,mpc885-i2c.

CPM2 i2c seems to be the same. However, i have no way to test this.

Quoted 10 lines

arch/powerpc/boot/dts/mpc885ads.dts line 225

Quoted 6 lines
arch/powerpc/boot/dts/mpc885ads.dts +5 -0
+#ifdef CONFIG_I2C_8XX
+	setbits32(&mpc8xx_immr->im_cpm.cp_pbpar, 0x00000030);
+	setbits32(&mpc8xx_immr->im_cpm.cp_pbdir, 0x00000030);
+	setbits16(&mpc8xx_immr->im_cpm.cp_pbodr, 0x0030);
+#endif
 

Please add this to mpc885ads_pins, rather than poking the registers directly. The relevant lines are:

Quoted 3 lines
	{CPM_PORTB, 26, CPM_PIN_OUTPUT},
	{CPM_PORTB, 27, CPM_PIN_OUTPUT},

I noticed cpm1_set_pin32, but this function don't seem to set the odr register. Will this be added? Then it would be:

{CPM_PORTB, 26, CPM_PIN_OUTPUT | CPM_PIN_OPENDRAIN}, {CPM_PORTB, 27, CPM_PIN_OUTPUT | CPM_PIN_OPENDRAIN},

Quoted 8 lines

arch/powerpc/boot/dts/mpc885ads.dts

Quoted 4 lines
arch/powerpc/boot/dts/mpc885ads.dts +3 -0
+	/* Select an arbitrary address.  Just make sure it is unique.
+	 */
+	out_8(&i2c->i2c_i2add, 0xfe);

It's a 7-bit address... and are you sure that 0x7e is unique? Does this driver even support slave operation?

It's in fact 0x7F << 1. The same value is used in the 2.4 driver and in u-boot, as well. Slave operation is not supported.

Quoted 2 lines

Why is an 8xx driver matching all i2c cpm (i.e. what about cpm2)?

With the suggested change to use fsl,cpm-command, the driver should be able to use both cpm1 and cpm2. The operation and structs for i2c are identical. The only difference might be the hack^wsupport for relocation.

Thanks,
Jochen

#3 lore raw
Quoted 16 lines · Jochen Friedrich
Quoted 6 lines
Quoted 6 lines
arch/powerpc/boot/dts/mpc885ads.dts +0 -0
index 8848e63..a526c02 100644
@@ -213,6 +213,15 @@
                 fsl,cpm-command = <0080>;
Quoted 9 lines

arch/powerpc/boot/dts/mpc885ads.dts line 227

Quoted 6 lines
arch/powerpc/boot/dts/mpc885ads.dts +3 -0
                 linux,network-index = <2>;
             };
+
+            i2c@860 {
+                device_type = "i2c";
 

No device_type.

Quoted 2 lines

Why? Documentation/powerpc/booting-without-of.txt says for I2C interfaces device_type is required and should be "i2c". Is this no longer true?

booting-without-of.txt should be changed.

Quoted 5 lines
Quoted 3 lines

Should be fsl,cpm-i2c. Is cpm2 i2c the same? If not, it should be fsl,cpm1-i2c. It's probably best to specify it anyway, along with fsl,mpc885-i2c.

CPM2 i2c seems to be the same. However, i have no way to test this.

OK, let's make the compatible "fsl,mpc885-i2c", "fsl,cpm1-i2c", "fsl,cpm-i2c".

For now, match on the last one, but if any differences pop up, we have the more specific ones.

Quoted 6 lines

I noticed cpm1_set_pin32, but this function don't seem to set the odr register. Will this be added? Then it would be:

{CPM_PORTB, 26, CPM_PIN_OUTPUT | CPM_PIN_OPENDRAIN}, {CPM_PORTB, 27, CPM_PIN_OUTPUT | CPM_PIN_OPENDRAIN},

Ah, missed that -- there's opendrain support for port E, but I missed that port B had it as well. Feel free to add it.

Quoted 4 lines
Quoted 2 lines

It's a 7-bit address... and are you sure that 0x7e is unique? Does this driver even support slave operation?

It's in fact 0x7F << 1.

Gah, I hate powerpc bit numbering, especially without the numbered-as-if-64-bit hack. I specifically looked at the manual before to see if it was shifted, saw "0-6", and concluded it wasn't. :-P

Quoted 2 lines

The same value is used in the 2.4 driver and
in u-boot, as well.

That doesn't mean that this isn't a good time to review what the code is doing. :-)

Quoted 1 line

Slave operation is not supported.

If slave operation isn't supported, how is this value used?

Quoted 6 lines
Quoted 1 line

Why is an 8xx driver matching all i2c cpm (i.e. what about cpm2)?

With the suggested change to use fsl,cpm-command, the driver should be able to use both cpm1 and cpm2. The operation and structs for i2c are identical. The only difference might be the hack^wsupport for relocation.

OK. Would that allow it to become one driver, rather than a wrapper and an algorithm?

-Scott

#4 lore raw
In reply to Jochen Friedrich
Quoted 11 lines · Jochen Friedrich
Quoted 8 lines

drivers/i2c/algos/i2c-algo-cpm.c line 154

Quoted 4 lines
drivers/i2c/algos/i2c-algo-cpm.c new file +3 -0
+	/* Select an arbitrary address.  Just make sure it is unique.
+	 */
+	out_8(&i2c->i2c_i2add, 0xfe);

It's a 7-bit address... and are you sure that 0x7e is unique? Does this driver even support slave operation?

It's in fact 0x7F << 1. The same value is used in the 2.4 driver and in u-boot, as well. Slave operation is not supported.

I'm not sure what exactly you are doing here, but 0x7f isn't a valid 7-bit I2C address.

Signature · 1 line
Jean Delvare
#5 lore raw

Hi Jean,

Quoted 8 lines · Jochen Friedrich
Quoted 7 lines
Quoted 7 lines

drivers/i2c/algos/i2c-algo-cpm.c line 154

Quoted 4 lines
drivers/i2c/algos/i2c-algo-cpm.c new file +3 -0
+	/* Select an arbitrary address.  Just make sure it is unique.
+	 */
+	out_8(&i2c->i2c_i2add, 0xfe);

It's a 7-bit address... and are you sure that 0x7e is unique? Does this driver even support slave operation?

Quoted 5 lines
Quoted 2 lines

It's in fact 0x7F << 1. The same value is used in the 2.4 driver and in u-boot, as well. Slave operation is not supported.

I'm not sure what exactly you are doing here, but 0x7f isn't a valid 7-bit I2C address.

That's most probably the reason why it is used everywhere in the CPM world (old driver, u-boot) ;-)

According to the documentation, the CPM enters a loopback mode as soon as a write access to the I2C address written to i2c_i2add takes place. This even happens if the CPM is set to master mode. So the only way to make sure there are no limitations to the I2C addresses which can be used is to use this invalid address. 0x00 can't be used either or no I2C broadcasts would be possible.

Quoted 1 line

From the MPC-823 documentation:

16.13.3.1.3 I2C Loopback Configuration. Loopback on the I2C controller is a special part of master mode operation with a device that does not contain internal addresses. Refer to Figure 16-127 for more information. To begin a loopback transmission, you must prepare a TX buffer descriptor with a data buffer N+1 bytes long, where N is the number of data bytes to be written back to the I2C controller. You must also prepare one or more RX buffer descriptors to receive the N bytes of data. The first byte of the TX buffer descriptor must contain the address of the MPC823 I2C device’s own address, which is in the I2CADD register, followed by the write bit asserted (R/W = 0). The remaining N bytes of the TX buffer descriptor contain the data to be sent and received by the I2C controller. Next, set the R bit in the TX buffer descriptor and the E bit in the RX buffer descriptor. Then set the W and L bits in the TX buffer descriptor. Setting the L bit causes a stop condition to be issued after this buffer is transmitted to conclude the operation. Set the I bit in the TX and RX buffer descriptors to enable the transmission and reception status to be updated in the I2CE register and to enable I2C transmit and receive interrupts to the core. You must then set the STR bit in the I2COM register to initiate the loopback operation.

Thanks,
Jochen