Skip to contentSkip to conversation

m68knommu: driver for Freescale Coldfire I2C controller.

PATCH Superseded Steven King 5 participants 7 messages Jan 11, 2010 – Mar 12, 2010

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

PATCH 1/1 m68knommu: driver for Freescale Coldfire I2C controller.

Add support for the I2C controller used on Freescale/Motorola Coldfire MCUs.

 drivers/i2c/busses/Kconfig   |   11 +
 drivers/i2c/busses/Makefile  |    1 +
 drivers/i2c/busses/i2c-mcf.c |  463 
++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 475 insertions(+), 0 deletions(-)
drivers/i2c/busses/Kconfig +3 -0
index 5f318ce..6caf7a0 100644
@@ -429,6 +429,17 @@ config I2C_MPC
 	  This driver can also be built as a module.  If so, the module
 	  will be called i2c-mpc.
 
+config I2C_MCF
+	tristate "Freescale Coldfire I2C driver"
+	depends on (M5206 || M5206e || M520x || M523x || M5249 || M527x || M528x || 

M5307 || M532x || M5407)
+ help

+	  This driver supports the I2C interface availible on some Freescale
+	  Coldfire processors (M520x, M523x, M5249, M5271, M5275, M528x,
+	  M5307, M532x, M5407).

+
+ This driver can be built as a module. If so, the module
+ will be called i2c-mcf.
+
config I2C_MV64XXX
tristate "Marvell mv64xxx I2C Controller" depends on (MV64X60 || PLAT_ORION) && EXPERIMENTAL

drivers/i2c/busses/Makefile +1 -0
index 302c551..c71349e 100644
@@ -41,6 +41,7 @@ obj-$(CONFIG_I2C_IMX)		+= i2c-imx.o
 obj-$(CONFIG_I2C_IOP3XX)	+= i2c-iop3xx.o
 obj-$(CONFIG_I2C_IXP2000)	+= i2c-ixp2000.o
 obj-$(CONFIG_I2C_MPC)		+= i2c-mpc.o
+obj-$(CONFIG_I2C_MCF)		+= i2c-mcf.o
 obj-$(CONFIG_I2C_MV64XXX)	+= i2c-mv64xxx.o
 obj-$(CONFIG_I2C_OCORES)	+= i2c-ocores.o
 obj-$(CONFIG_I2C_OMAP)		+= i2c-omap.o
drivers/i2c/busses/i2c-mcf.c new file +463 -0

463 lines not on this page · raw message

#1 lore raw
Quoted 7 lines · Steven King

Add support for the I2C controller used on Freescale/Motorola Coldfire MCUs.

 drivers/i2c/busses/Kconfig   |   11 +
 drivers/i2c/busses/Makefile  |    1 +
 drivers/i2c/busses/i2c-mcf.c |  463 ++++++++++++++++++++++++++++++++++++++++++

Please come up with a longer name. i2c-coldfire, for example.

Signature · 1 line
Jean Delvare
#2 lore raw

PATCH v2 1/1 m68knommu: driver for Freescale Coldfire I2C controller.

Changes for this version:

	rename drivers/i2c/busses/i2c-mcf.c to drivers/i2c/busses/i2c-coldfire.c
	use I2C_COLDFIRE in drivers/i2c/busses/{Kconfig,Makefile}

------

Add support for the I2C controller used on Freescale/Motorola Coldfire MCUs.

 drivers/i2c/busses/Kconfig        |   11 +
 drivers/i2c/busses/Makefile       |    1 +
 drivers/i2c/busses/i2c-coldfire.c |  463 +++++++++++++++++++++++++++++++++++++
 3 files changed, 475 insertions(+), 0 deletions(-)
drivers/i2c/busses/Kconfig +11 -0
index 5f318ce..83c2904 100644
@@ -320,6 +320,17 @@ config I2C_BLACKFIN_TWI_CLK_KHZ
 	help
 	  The unit of the TWI clock is kHz.
 
+config I2C_COLDFIRE
+	tristate "Freescale Coldfire I2C driver"
+	depends on (M5206 || M5206e || M520x || M523x || M5249 || M527x || M528x || M5307 || M532x || M5407)
+	help
+	  This driver supports the I2C interface available on some Freescale
+	  Coldfire processors (M520x, M523x, M5249, M5271, M5275, M528x,
+	  M5307, M532x, M5407).
+
+	  This driver can be built as a module.  If so, the module
+	  will be called i2c-coldfire.
+
 config I2C_CPM
 	tristate "Freescale CPM1 or CPM2 (MPC8xx/826x)"
 	depends on (CPM1 || CPM2) && OF_I2C
drivers/i2c/busses/Makefile +1 -0
index 302c551..0185333 100644
@@ -31,6 +31,7 @@ obj-$(CONFIG_I2C_POWERMAC)	+= i2c-powermac.o
 obj-$(CONFIG_I2C_AT91)		+= i2c-at91.o
 obj-$(CONFIG_I2C_AU1550)	+= i2c-au1550.o
 obj-$(CONFIG_I2C_BLACKFIN_TWI)	+= i2c-bfin-twi.o
+obj-$(CONFIG_I2C_COLDFIRE)	+= i2c-coldfire.o
 obj-$(CONFIG_I2C_CPM)		+= i2c-cpm.o
 obj-$(CONFIG_I2C_DAVINCI)	+= i2c-davinci.o
 obj-$(CONFIG_I2C_DESIGNWARE)	+= i2c-designware.o
drivers/i2c/busses/i2c-coldfire.c new file +463 -0

463 lines not on this page · raw message

#3 lore raw
Quoted 9 lines · Steven King

Changes for this version:

	rename drivers/i2c/busses/i2c-mcf.c to drivers/i2c/busses/i2c-coldfire.c
	use I2C_COLDFIRE in drivers/i2c/busses/{Kconfig,Makefile}

------

Add support for the I2C controller used on Freescale/Motorola Coldfire MCUs.

The commit messsage should go first, the changelog and other stuff that won't go in should go beflore the --- line.

Quoted 126 lines
 drivers/i2c/busses/Kconfig        |   11 +
 drivers/i2c/busses/Makefile       |    1 +
 drivers/i2c/busses/i2c-coldfire.c |  463 +++++++++++++++++++++++++++++++++++++
 3 files changed, 475 insertions(+), 0 deletions(-)
drivers/i2c/busses/Kconfig +11 -0
index 5f318ce..83c2904 100644
@@ -320,6 +320,17 @@ config I2C_BLACKFIN_TWI_CLK_KHZ
 	help
 	  The unit of the TWI clock is kHz.
 
+config I2C_COLDFIRE
+	tristate "Freescale Coldfire I2C driver"
+	depends on (M5206 || M5206e || M520x || M523x || M5249 || M527x || M528x || M5307 || M532x || M5407)
+	help
+	  This driver supports the I2C interface available on some Freescale
+	  Coldfire processors (M520x, M523x, M5249, M5271, M5275, M528x,
+	  M5307, M532x, M5407).
+
+	  This driver can be built as a module.  If so, the module
+	  will be called i2c-coldfire.
+
 config I2C_CPM
 	tristate "Freescale CPM1 or CPM2 (MPC8xx/826x)"
 	depends on (CPM1 || CPM2) && OF_I2C
drivers/i2c/busses/Makefile +1 -0
index 302c551..0185333 100644
@@ -31,6 +31,7 @@ obj-$(CONFIG_I2C_POWERMAC)	+= i2c-powermac.o
 obj-$(CONFIG_I2C_AT91)		+= i2c-at91.o
 obj-$(CONFIG_I2C_AU1550)	+= i2c-au1550.o
 obj-$(CONFIG_I2C_BLACKFIN_TWI)	+= i2c-bfin-twi.o
+obj-$(CONFIG_I2C_COLDFIRE)	+= i2c-coldfire.o
 obj-$(CONFIG_I2C_CPM)		+= i2c-cpm.o
 obj-$(CONFIG_I2C_DAVINCI)	+= i2c-davinci.o
 obj-$(CONFIG_I2C_DESIGNWARE)	+= i2c-designware.o
drivers/i2c/busses/i2c-coldfire.c new file +81 -0
new file mode 100644
index 0000000..27f0d0b
@@ -0,0 +1,463 @@
+/* Freescale/Motorola Coldfire I2C driver.
+ *
+ * Copyright 2010 Steven King <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+
+#include <asm/mcfi2c.h>
+
+#define	DRIVER_NAME "mcfi2c"
+
+#define	MCFI2C_ADR			0x00
+#define	MCFI2C_FDR			0x04
+#define	MCFI2C_CR			0x08
+#define		MCFI2C_CR_IEN		0x80
+#define		MCFI2C_CR_IIEN		0x40
+#define		MCFI2C_CR_MSTA		0x20
+#define		MCFI2C_CR_MTX		0x10
+#define		MCFI2C_CR_TXAK		0x08
+#define		MCFI2C_CR_RSTA		0x04
+#define	MCFI2C_DR			0x10
+#define	MCFI2C_SR			0x0C
+#define		MCFI2C_SR_ICF		0x80
+#define		MCFI2C_SR_IAAS		0x40
+#define		MCFI2C_SR_IBB		0x20
+#define		MCFI2C_SR_IAL		0x10
+#define		MCFI2C_SR_SRW		0x04
+#define		MCFI2C_SR_IIF		0x02
+#define		MCFI2C_SR_RXAK		0x01
+
+#define	DEFAULT_I2C_BUS_SPEED		100000
+
+struct mcfi2c {
+	struct i2c_adapter	adapter;
+	void __iomem		*iobase;
+	int			irq;
+	struct clk		*clk;
+	struct completion	completion;
+};
+
+static u8 mcfi2c_rd_cr(struct mcfi2c *mcfi2c)
+{
+	return readb(mcfi2c->iobase + MCFI2C_CR);
+}
+
+static void mcfi2c_wr_cr(struct mcfi2c *mcfi2c, u8 val)
+{
+	writeb(val, mcfi2c->iobase + MCFI2C_CR);
+}
+
+static u8 mcfi2c_rd_sr(struct mcfi2c *mcfi2c)
+{
+	return readb(mcfi2c->iobase + MCFI2C_SR);
+}
+
+static void mcfi2c_wr_sr(struct mcfi2c *mcfi2c, u8 val)
+{
+	writeb(val, mcfi2c->iobase + MCFI2C_SR);
+}

drivers/i2c/busses/i2c-coldfire.c line 91

Quoted 10 lines
drivers/i2c/busses/i2c-coldfire.c new file +10 -0
+
+static u8 mcfi2c_rd_dr(struct mcfi2c *mcfi2c)
+{
+	return readb(mcfi2c->iobase + MCFI2C_DR);
+}
+
+static void mcfi2c_wr_dr(struct mcfi2c *mcfi2c, u8 val)
+{
+	writeb(val, mcfi2c->iobase + MCFI2C_DR);
+}

not entirely sure why you bother wrapping these accesses, but I'm not going to block this driver just becuase I don't like it.

Quoted 28 lines
drivers/i2c/busses/i2c-coldfire.c new file +28 -0
+static void mcfi2c_start(struct mcfi2c *mcfi2c)
+{
+	mcfi2c_wr_cr(mcfi2c, MCFI2C_CR_IEN | MCFI2C_CR_IIEN | MCFI2C_CR_MSTA |
+		     MCFI2C_CR_MTX);
+}
+
+static void mcfi2c_repeat_start(struct mcfi2c *mcfi2c)
+{
+	mcfi2c_wr_cr(mcfi2c, MCFI2C_CR_IEN | MCFI2C_CR_IIEN | MCFI2C_CR_MSTA |
+		     MCFI2C_CR_MTX | MCFI2C_CR_RSTA);
+}
+
+static void mcfi2c_stop(struct mcfi2c *mcfi2c)
+{
+	mcfi2c_wr_cr(mcfi2c, MCFI2C_CR_IEN);
+}
+
+static void mcfi2c_tx_ack(struct mcfi2c *mcfi2c)
+{
+	mcfi2c_wr_cr(mcfi2c, MCFI2C_CR_IEN | MCFI2C_CR_IIEN | MCFI2C_CR_MSTA);
+}
+
+static void mcfi2c_tx_nak(struct mcfi2c *mcfi2c)
+{
+	mcfi2c_wr_cr(mcfi2c, MCFI2C_CR_IEN | MCFI2C_CR_IIEN | MCFI2C_CR_MSTA |
+		     MCFI2C_CR_TXAK);
+}
+

drivers/i2c/busses/i2c-coldfire.c line 130

Quoted 10 lines
drivers/i2c/busses/i2c-coldfire.c new file +10 -0
+static irqreturn_t mcfi2c_irq_handler(int this_irq, void *dev_id)
+{
+	struct mcfi2c *mcfi2c = dev_id;
+
+	/* clear interrupt */
+	mcfi2c_wr_sr(mcfi2c, 0);
+	complete(&mcfi2c->completion);
+
+	return IRQ_HANDLED;
+}

I'm interested in why you don't just handle the interrupt here and wake the thread once all the data is handled?

Quoted 186 lines
drivers/i2c/busses/i2c-coldfire.c new file +186 -0
+static void mcfi2c_reset(struct mcfi2c *mcfi2c)
+{
+	mcfi2c_wr_cr(mcfi2c, 0);
+	mcfi2c_wr_cr(mcfi2c, MCFI2C_CR_IEN | MCFI2C_CR_MSTA);
+	mcfi2c_rd_dr(mcfi2c);
+	mcfi2c_wr_sr(mcfi2c, 0);
+	mcfi2c_wr_cr(mcfi2c, 0);
+	mcfi2c_wr_cr(mcfi2c, MCFI2C_CR_IEN);
+}
+
+static void mcfi2c_wait_for_bus_idle(struct mcfi2c *mcfi2c)
+{
+	if (mcfi2c_rd_sr(mcfi2c) & MCFI2C_SR_IBB) {
+		unsigned long timeout = jiffies + HZ / 2;
+		do {
+			cond_resched();
+			if (time_after(jiffies, timeout)) {
+				mcfi2c_reset(mcfi2c);
+				break;
+			}
+		} while (mcfi2c_rd_sr(mcfi2c) & MCFI2C_SR_IBB);
+	}
+}
+
+static int mcfi2c_wait_for_bus_busy(struct mcfi2c *mcfi2c)
+{
+	u8 sr;
+	while (!((sr = mcfi2c_rd_sr(mcfi2c)) & MCFI2C_SR_IBB))
+		if (sr & MCFI2C_SR_IAL) {
+			mcfi2c_reset(mcfi2c);
+			return -EIO;
+		}
+	return 0;
+}
+
+static int mcfi2c_xmit(struct mcfi2c *mcfi2c, u16 addr, u16 flags, u8 *buf,
+		       u16 len, int timeout, int more)
+{
+	if (!(mcfi2c_rd_cr(mcfi2c) & MCFI2C_CR_MSTA)) {
+		mcfi2c_wait_for_bus_idle(mcfi2c);
+
+		INIT_COMPLETION(mcfi2c->completion);
+		mcfi2c_start(mcfi2c);
+
+		if (mcfi2c_wait_for_bus_busy(mcfi2c))
+			return -EIO;
+	}
+
+	mcfi2c_wr_dr(mcfi2c, (addr << 1) | (flags & I2C_M_RD));
+	while (wait_for_completion_timeout(&mcfi2c->completion, timeout)) {
+		u8 sr = mcfi2c_rd_sr(mcfi2c);
+		if (sr & MCFI2C_SR_IAL) {
+			mcfi2c_wr_sr(mcfi2c, ~MCFI2C_SR_IAL);
+			return -EIO;
+		} else if (mcfi2c_rd_cr(mcfi2c) & MCFI2C_CR_MTX) {
+			if (sr & MCFI2C_SR_RXAK) {
+				mcfi2c_stop(mcfi2c);
+				return -EIO;
+			} else if (flags & I2C_M_RD) {
+				if (len > 1)
+					mcfi2c_tx_ack(mcfi2c);
+				else
+					mcfi2c_tx_nak(mcfi2c);
+				/* dummy read */
+				mcfi2c_rd_dr(mcfi2c);
+			} else if (len--) {
+				mcfi2c_wr_dr(mcfi2c, *buf++);
+			} else {
+				if (more)
+					mcfi2c_repeat_start(mcfi2c);
+				else
+					mcfi2c_stop(mcfi2c);
+				return 0;
+			}
+		} else if (--len) {
+			if (!(len > 1))
+				mcfi2c_tx_nak(mcfi2c);
+			*buf++ = mcfi2c_rd_dr(mcfi2c);
+		} else {
+			if (more)
+				mcfi2c_repeat_start(mcfi2c);
+			else
+				mcfi2c_stop(mcfi2c);
+			*buf++ = mcfi2c_rd_dr(mcfi2c);
+			return 0;
+		}
+	}
+	mcfi2c_stop(mcfi2c);
+
+	return -ETIMEDOUT;
+}
+
+static int mcfi2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
+		int num)
+{
+	struct mcfi2c *mcfi2c = i2c_get_adapdata(adapter);
+	int cnt = 0;
+	int status;
+	int retries;
+
+	while (num--) {
+		retries = adapter->retries;
+		if (msgs->flags & ~I2C_M_RD)
+			return -EINVAL;
+		do {
+			status = mcfi2c_xmit(mcfi2c, msgs->addr, msgs->flags,
+					     msgs->buf, msgs->len,
+					     adapter->timeout, num);
+		} while (status && retries--);
+		if (status)
+			return status;
+		++cnt;
+		++msgs;
+	}
+
+	return cnt;
+}
+
+static u32 mcfi2c_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm mcfi2c_algo = {
+	.master_xfer	= mcfi2c_xfer,
+	.functionality	= mcfi2c_func,
+};
+
+static const u16 mcfi2c_fdr[] = {
+	  28,   30,   34,   40,   44,   48,   56,   68,
+	  80,   88,  104,  128,  144,  160,  192,  240,
+	 288,  320,  384,  480,  576,  640,  768,  960,
+	1152, 1280, 1536, 1920, 2304, 2560, 3072, 3840,
+	  20,   22,   24,   26,   28,   32,   36,   40,
+	  48,   56,   64,   72,   80,   96,  112,  128,
+	 160,  192,  224,  256,  320,  384,  448,  512,
+	 640,  768,  896, 1024, 1280, 1536, 1792, 2048
+};
+
+static u8 __devinit mcfi2c_calc_fdr(struct mcfi2c *mcfi2c,
+				    struct mcfi2c_platform_data *pdata)
+{
+	u32 bitrate = (pdata && pdata->bitrate) ?
+			pdata->bitrate : DEFAULT_I2C_BUS_SPEED;
+	int div = clk_get_rate(mcfi2c->clk)/bitrate;
+	int r = 0, i = 0;
+
+	do
+		if (abs(mcfi2c_fdr[i] - div) < abs(mcfi2c_fdr[r] - div))
+			r = i;
+	while (++i < ARRAY_SIZE(mcfi2c_fdr));
+
+	return r;
+}
+
+static int __devinit mcfi2c_probe(struct platform_device *pdev)
+{
+	struct mcfi2c *mcfi2c;
+	struct resource *res;
+	int status;
+
+	mcfi2c = kzalloc(sizeof(*mcfi2c), GFP_KERNEL);
+	if (!mcfi2c) {
+		dev_dbg(&pdev->dev, "kzalloc failed\n");
+
+		return -ENOMEM;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_dbg(&pdev->dev, "platform_get_resource failed\n");
+		status = -ENXIO;
+		goto fail0;
+	}
+
+	if (!request_mem_region(res->start, resource_size(res), pdev->name)) {
+		dev_dbg(&pdev->dev, "request_mem_region failed\n");
+		status = -EBUSY;
+		goto fail0;
+	}
+
+	mcfi2c->iobase = ioremap(res->start, resource_size(res));
+	if (!mcfi2c->iobase) {
+		dev_dbg(&pdev->dev, "ioremap failed\n");
+		status = -ENOMEM;
+		goto fail1;

drivers/i2c/busses/i2c-coldfire.c line 327

Quoted 10 lines
drivers/i2c/busses/i2c-coldfire.c new file +10 -0
+	}
+
+	mcfi2c->irq = platform_get_irq(pdev, 0);
+	if (mcfi2c->irq < 0) {
+		dev_dbg(&pdev->dev, "platform_get_irq failed\n");
+		status = -ENXIO;
+		goto fail2;
+	}
+	status = request_irq(mcfi2c->irq, mcfi2c_irq_handler, IRQF_DISABLED,
+			     pdev->name, mcfi2c);

do you really need IRQF_DISABLED here? your irq handler hardly does anything.

drivers/i2c/busses/i2c-coldfire.c line 333

Quoted 6 lines
drivers/i2c/busses/i2c-coldfire.c new file +6 -0
+	if (status) {
+		dev_dbg(&pdev->dev, "request_irq failed\n");
+		goto fail2;
+	}
+
+	mcfi2c->clk = clk_get(&pdev->dev, "i2c_clk");

hmm, think the default device clock should be findable by clk_get(dev, NULL).

Quoted 130 lines
drivers/i2c/busses/i2c-coldfire.c new file +130 -0
+	if (IS_ERR(mcfi2c->clk)) {
+		dev_dbg(&pdev->dev, "clk_get failed\n");
+		status = PTR_ERR(mcfi2c->clk);
+		goto fail3;
+	}
+	clk_enable(mcfi2c->clk);
+
+	platform_set_drvdata(pdev, mcfi2c);
+
+	init_completion(&mcfi2c->completion);
+
+	writeb(mcfi2c_calc_fdr(mcfi2c, pdev->dev.platform_data),
+	       mcfi2c->iobase + MCFI2C_FDR);
+
+	writeb(0x00, mcfi2c->iobase + MCFI2C_ADR);
+
+	mcfi2c_wr_cr(mcfi2c, MCFI2C_CR_IEN);
+
+	/* if the bus busy (IBB) is set, reset the controller */
+	if (mcfi2c_rd_sr(mcfi2c) & MCFI2C_SR_IBB)
+		mcfi2c_reset(mcfi2c);
+
+	mcfi2c->adapter.algo		= &mcfi2c_algo;
+	mcfi2c->adapter.class		= I2C_CLASS_HWMON | I2C_CLASS_SPD;
+	mcfi2c->adapter.dev.parent	= &pdev->dev;
+	mcfi2c->adapter.nr		= pdev->id;
+	mcfi2c->adapter.retries		= 2;
+	snprintf(mcfi2c->adapter.name, sizeof(mcfi2c->adapter.name),
+			DRIVER_NAME ".%d", pdev->id);
+
+	i2c_set_adapdata(&mcfi2c->adapter, mcfi2c);
+
+	status = i2c_add_numbered_adapter(&mcfi2c->adapter);
+	if (status < 0) {
+		dev_dbg(&pdev->dev, "i2c_add_numbered_adapter failed\n");
+		goto fail4;
+	}
+	dev_info(&pdev->dev, "Coldfire I2C bus driver\n");
+
+	return 0;
+
+fail4:
+	clk_disable(mcfi2c->clk);
+	clk_put(mcfi2c->clk);
+fail3:
+	free_irq(mcfi2c->irq, mcfi2c);
+fail2:
+	iounmap(mcfi2c->iobase);
+fail1:
+	release_mem_region(res->start, resource_size(res));
+fail0:
+	kfree(mcfi2c);
+
+	return status;
+}
+
+static int __devexit mcfi2c_remove(struct platform_device *pdev)
+{
+	struct mcfi2c *mcfi2c = platform_get_drvdata(pdev);
+	struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+	/* disable the hardware */
+	mcfi2c_wr_cr(mcfi2c, 0);
+
+	platform_set_drvdata(pdev, NULL);
+	i2c_del_adapter(&mcfi2c->adapter);
+	clk_disable(mcfi2c->clk);
+	clk_put(mcfi2c->clk);
+	free_irq(mcfi2c->irq, mcfi2c);
+	iounmap(mcfi2c->iobase);
+	release_mem_region(res->start, resource_size(res));
+	kfree(mcfi2c);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int mcfi2c_suspend(struct device *dev)
+{
+	struct mcfi2c *mcfi2c = platform_get_drvdata(to_platform_device(dev));
+
+	mcfi2c_wr_cr(mcfi2c, 0);
+	clk_disable(mcfi2c->clk);
+
+	return 0;
+}
+
+static int mcfi2c_resume(struct device *dev)
+{
+	struct mcfi2c *mcfi2c = platform_get_drvdata(to_platform_device(dev));
+
+	clk_enable(mcfi2c->clk);
+	mcfi2c_wr_cr(mcfi2c, MCFI2C_CR_IEN);
+
+	return 0;
+}
+
+static struct dev_pm_ops mcfi2c_dev_pm_ops = {
+	.suspend	= mcfi2c_suspend,
+	.resume		= mcfi2c_resume,
+};
+
+#define	MCFI2C_DEV_PM_OPS (&mcfi2c_dev_pm_ops)
+#else
+#define	MCFI2C_DEV_PM_OPS NULL
+#endif
+
+static struct platform_driver mcfi2c_driver = {
+	.driver.name	= DRIVER_NAME,
+	.driver.owner	= THIS_MODULE,
+	.driver.pm	= MCFI2C_DEV_PM_OPS,
+	.remove		= __devexit_p(mcfi2c_remove),
+};
+
+static int __init mcfi2c_init(void)
+{
+	return platform_driver_probe(&mcfi2c_driver, mcfi2c_probe);
+}
+module_init(mcfi2c_init);
+
+static void __exit mcfi2c_exit(void)
+{
+	platform_driver_unregister(&mcfi2c_driver);
+}
+module_exit(mcfi2c_exit);
+
+MODULE_AUTHOR("Steven King <[email protected]>");
+MODULE_DESCRIPTION("I2C-Bus support for Freescale Coldfire processors");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRIVER_NAME);
Signature · 3 lines
Ben ([email protected], http://www.fluff.org/)

  'a smiley only costs 4 bytes'
#4 lore raw
Quoted 7 lines · On Sunday 24 January 2010 07:15:19 you wrote:
Quoted 6 lines · Steven King

Changes for this version:

	rename drivers/i2c/busses/i2c-mcf.c to drivers/i2c/busses/i2c-coldfire.c
	use I2C_COLDFIRE in drivers/i2c/busses/{Kconfig,Makefile}

------

Quoted 7 lines
Quoted 4 lines

Add support for the I2C controller used on Freescale/Motorola Coldfire MCUs.

The commit messsage should go first, the changelog and other stuff that won't go in should go beflore the --- line.

My bad, I think I was paying more attention to making sure this mailer didn't line wrap on me. I can repost if you want.

Quoted 5 lines
Quoted 5 lines
drivers/i2c/busses/i2c-coldfire.c new file +5 -0
+static irqreturn_t mcfi2c_irq_handler(int this_irq, void *dev_id)
+{
+	struct mcfi2c *mcfi2c = dev_id;
+
+	/* clear interrupt */
Quoted 8 lines

drivers/i2c/busses/i2c-coldfire.c line 130

Quoted 5 lines
drivers/i2c/busses/i2c-coldfire.c new file +5 -0
+	mcfi2c_wr_sr(mcfi2c, 0);
+	complete(&mcfi2c->completion);
+
+	return IRQ_HANDLED;
+}

I'm interested in why you don't just handle the interrupt here and wake the thread once all the data is handled?

No particular reason; when I started working on this I looked at how some of the other drivers in drivers/i2c/busses were implemented, found one whose workings I could understand without knowing anything about that particular SoC (which one I don't remember) and used it as a model to adapt the i2c code I use with other Freescale/Motorola MCUs that don't run linux (there is very little difference in the i2c controller on an 8-bit hc08, 16 bit hc11/12, 32bit Coldfire v1 and the Coldfire v2[+] that are currently supported). So other than having easy to understand (for me atleast) code that shared a lot of similarity with the code I use for the some of the other systems I code for, no real reason. That and I find statefull irq handlers disconcerting.

Quoted 5 lines

drivers/i2c/busses/i2c-coldfire.c line 327

Quoted 2 lines
drivers/i2c/busses/i2c-coldfire.c new file +2 -0
+	status = request_irq(mcfi2c->irq, mcfi2c_irq_handler, IRQF_DISABLED,
+			     pdev->name, mcfi2c);

do you really need IRQF_DISABLED here? your irq handler hardly does anything.

Yes, without it, I was getting a spurious interrupt (been there, done that).

Quoted 9 lines

drivers/i2c/busses/i2c-coldfire.c line 333

Quoted 6 lines
drivers/i2c/busses/i2c-coldfire.c new file +6 -0
+	if (status) {
+		dev_dbg(&pdev->dev, "request_irq failed\n");
+		goto fail2;
+	}
+
+	mcfi2c->clk = clk_get(&pdev->dev, "i2c_clk");

hmm, think the default device clock should be findable by clk_get(dev, NULL).

Interesting. Again, I had looked at the existing code in drivers/i2c/busses
to see what the other drivers were doing and most were passing an id string.

Its a trivial change so its no big deal, but I'm curious, absent anything in Documentation, if the bulk of the existing code isn't documentation for the correct use of an api, then what is?

Signature · 8 lines
Steven King -- sfking at fdwdc dot com
_______________________________________________
uClinux-dev mailing list
[email protected]
http://mailman.uclinux.org/mailman/listinfo/uclinux-dev
This message was resent by [email protected]
To unsubscribe see:
http://mailman.uclinux.org/mailman/options/uclinux-dev
#5 lore raw

Hello all,

Quoted 5 lines · Steven King
Quoted 5 lines
Quoted 5 lines

Add support for the I2C controller used on Freescale/Motorola Coldfire MCUs.

What's the status of this ?

I need to use i2c for a coldfire uclinux project (with a mcf5484) and I now have 3 different coldfire i2c drivers, none of which is in mainline.

i2c-mcf.c (from uClinux-dist-20090618, but not in http://git.kernel.org/?p=linux/kernel/git/gerg/m68knommu.git;a=summary)
i2c-mcf548x.c (from ltib-m5475evb-20080808, found as "Linux BSP for MCF5484LITE, MCF5475/85EVB" at http://www.freescale.com/webapp/sps/site/prod_summary.jsp?code=MCF548X&fpsp=1&tab=Design_Tools_Tab)
i2c-coldfire.c (from http://lkml.org/lkml/2010/1/11/165)

I like to work with mainline sources to be be able to contribute to and benefit from collective work.

Which one has the best chances to be put in mainline ?

Best regards

Philippe
_______________________________________________
uClinux-dev mailing list [email protected]
http://mailman.uclinux.org/mailman/listinfo/uclinux-dev
This message was resent by [email protected] To unsubscribe see:
http://mailman.uclinux.org/mailman/options/uclinux-dev

#6 lore raw
Quoted 7 lines · Philippe De Muyter

Hello all,

Quoted 4 lines · Steven King
Quoted 4 lines
Quoted 4 lines

Add support for the I2C controller used on Freescale/Motorola Coldfire MCUs.

Quoted 8 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line

What's the status of this ?

I need to use i2c for a coldfire uclinux project (with a mcf5484) and I now have 3 different coldfire i2c drivers, none of which is in mainline.

i2c-mcf.c (from uClinux-dist-20090618, but not in http://git.kernel.org/?p=linux/kernel/git/gerg/m68knommu.git;a=summary)

It seems I use that one based on the filename.

Quoted 7 lines

i2c-mcf548x.c (from ltib-m5475evb-20080808, found as "Linux BSP for MCF5484LITE, MCF5475/85EVB" at http://www.freescale.com/webapp/sps/site/prod_summary.jsp?code=MCF548X&fpsp=1&tab=Design_Tools_Tab)
i2c-coldfire.c (from http://lkml.org/lkml/2010/1/11/165)

I like to work with mainline sources to be be able to contribute to and benefit from collective work.

Which one has the best chances to be put in mainline ?

No idea.

I am using this one on a 5271:

http://www.bitshrine.org/gpp/0006-I2C-device-driver.patch
http://www.bitshrine.org/gpp/0043-I2C-bug-fix.patch

No problems so far.

This is the patch that I use on top of
git://git.kernel.org/pub/scm/linux/kernel/git/geert/linux-m68k.git

arch/m68k/include/asm/m527xsim.h +39 -0
diff -urN build-2.6.29-1-m68k-uclinux-target1-nfs/arch/m68k/include/asm/m527xsim.h build-2.6.29-1-m68k-uclinux-target1/arch/m68k/include/asm/m527xsim.h
@@ -248,5 +248,44 @@
 #define	MCF_RCR_SWRESET		0x80		/* Software reset bit */
 #define	MCF_RCR_FRCSTOUT	0x40		/* Force external reset */
 
+/*********************************************************************
+*
+* I2C Module (I2C) (Stolen from m5301xsim.h)
+*
+*********************************************************************/
+/* Register read/write macros */
+#ifdef CONFIG_M5271
+#define MCF_I2C_I2ADR           (volatile unsigned char *)(MCF_MBAR + 0x300)
+#define MCF_I2C_I2FDR           (volatile unsigned char *)(MCF_MBAR + 0x304)
+#define MCF_I2C_I2CR            (volatile unsigned char *)(MCF_MBAR + 0x308)
+#define MCF_I2C_I2SR            (volatile unsigned char *)(MCF_MBAR + 0x30C)
+#define MCF_I2C_I2DR            (volatile unsigned char *)(MCF_MBAR + 0x310)
+
+/* Bit definitions and macros for I2AR */
+#define MCF_I2C_I2AR_ADR(x)     (((x)&0x7F)<<1)
+
+/* Bit definitions and macros for I2FDR */
+#define MCF_I2C_I2FDR_IC(x)     (((x)&0x3F))
+
+/* Bit definitions and macros for I2CR */
+#define MCF_I2C_I2CR_RSTA       (0x04)
+#define MCF_I2C_I2CR_TXAK       (0x08)
+#define MCF_I2C_I2CR_MTX        (0x10)
+#define MCF_I2C_I2CR_MSTA       (0x20)
+#define MCF_I2C_I2CR_IIEN       (0x40)
+#define MCF_I2C_I2CR_IEN        (0x80)
+
+/* Bit definitions and macros for I2SR */
+#define MCF_I2C_I2SR_RXAK       (0x01)
+#define MCF_I2C_I2SR_IIF        (0x02)
+#define MCF_I2C_I2SR_SRW        (0x04)
+#define MCF_I2C_I2SR_IAL        (0x10)
+#define MCF_I2C_I2SR_IBB        (0x20)
+#define MCF_I2C_I2SR_IAAS       (0x40)
+#define MCF_I2C_I2SR_ICF        (0x80)
+
+/* Bit definitions and macros for I2DR */
+#define MCF_I2C_I2DR_DATA(x)    (x)
+#endif /* I2C Module for CONFIG_M5271 */
 /****************************************************************************/
 #endif	/* m527xsim_h */
drivers/i2c/busses/Kconfig +10 -0
diff -urN build-2.6.29-1-m68k-uclinux-target1-nfs/drivers/i2c/busses/Kconfig build-2.6.29-1-m68k-uclinux-target1/drivers/i2c/busses/Kconfig
@@ -417,6 +417,16 @@
 	  This driver is deprecated and will be dropped soon. Use i2c-gpio
 	  instead.
 
+config I2C_MCF
+	tristate "MCF ColdFire"
+	depends on I2C && EXPERIMENTAL
+	help
+	  If you say yes to this option, support will be included for the
+	  I2C on most ColdFire CPUs
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called i2c-mcf.
+
 config I2C_MPC
 	tristate "MPC107/824x/85xx/52xx/86xx"
 	depends on PPC32
drivers/i2c/busses/Makefile +1 -0
diff -urN build-2.6.29-1-m68k-uclinux-target1-nfs/drivers/i2c/busses/Makefile build-2.6.29-1-m68k-uclinux-target1/drivers/i2c/busses/Makefile
@@ -71,6 +71,7 @@
 obj-$(CONFIG_I2C_STUB)		+= i2c-stub.o
 obj-$(CONFIG_SCx200_ACB)	+= scx200_acb.o
 obj-$(CONFIG_SCx200_I2C)	+= scx200_i2c.o
+obj-$(CONFIG_I2C_MCF)		+= i2c-mcf.o
 
 ifeq ($(CONFIG_I2C_DEBUG_BUS),y)
 EXTRA_CFLAGS += -DDEBUG
drivers/i2c/busses/i2c-mcf.c +601 -0

601 lines not on this page · raw message

drivers/i2c/busses/i2c-mcf.h +52 -0

52 lines not on this page · raw message

I think that __I2C_MCF5282_H__ should be __I2C_MCF_H__ instead, but well what can you do.

Signature · 8 lines
Len Sorensen
_______________________________________________
uClinux-dev mailing list
[email protected]
http://mailman.uclinux.org/mailman/listinfo/uclinux-dev
This message was resent by [email protected]
To unsubscribe see:
http://mailman.uclinux.org/mailman/options/uclinux-dev