linux-i2c.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH V3] m68knommu: driver for Freescale Coldfire I2C controller.
@ 2012-05-17  2:10 Steven King
       [not found] ` <201205161910.36693.sfking-xS0NTnu2YfYAvxtiuMwx3w@public.gmane.org>
  0 siblings, 1 reply; 5+ messages in thread
From: Steven King @ 2012-05-17  2:10 UTC (permalink / raw)
  To: linux-i2c; +Cc: Wolfram Sang, uClinux development list, Ben Dooks, gerg

D'oh!  I really dropped the ball on this, but I figure better late than never ;-).

Changes since V2:

drivers/i2c/busses/i2c-coldfire.c:
* As Ben suggested, making the interrupt handler do most of the message
  processing and wake the thread when its done vastly improves performance.
* preliminary support for PM_RUNTIME; but as there isn't arch support for for 
  PM_RUNTIME it doesn't do anything yet.
* fixed a bug when the driver would hang on waiting for bus busy if the bus
  never went busy.

drivers/i2c/busses/Kconfig:
* its easier to list the Coldfire MCUs that don't have I2C.

arch/m68k/include/asm/mcfi2c.h:
* moved the defines for the various Coldfire MCUs to the specific header
   file for the various Coldfire MCUs. 


Support for the Freescale Coldfire I2C controller.

Signed-off-by: Steven King <sfking@fedc.com>
---
 arch/m68k/include/asm/mcfi2c.h    |   15 ++
 drivers/i2c/busses/Kconfig        |   10 +
 drivers/i2c/busses/Makefile       |    1 +
 drivers/i2c/busses/i2c-coldfire.c |  497 +++++++++++++++++++++++++++++++++++++
 4 files changed, 523 insertions(+)

diff --git a/arch/m68k/include/asm/mcfi2c.h b/arch/m68k/include/asm/mcfi2c.h
new file mode 100644
index 0000000..24b0453
--- /dev/null
+++ b/arch/m68k/include/asm/mcfi2c.h
@@ -0,0 +1,15 @@
+/*
+ * Definitions for Coldfire I2C interface
+*/
+#ifndef mcfi2c_h
+#define mcfi2c_h
+
+/**
+ * struct mcfi2c_platform_data - platform data for the coldfire i2c driver
+ * @bitrate: bitrate to use for this i2c controller.
+*/
+struct mcfi2c_platform_data {
+	u32	bitrate;
+};
+
+#endif /* mcfi2c_h */
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index d2c5095..159404e 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -327,6 +327,16 @@ 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 !M5272
+	help
+	  This driver supports the I2C interface availible on most Freescale
+	  Coldfire processors.
+
+	  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
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 569567b..2c88c4a 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -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_PLATFORM)	+= i2c-designware-platform.o
diff --git a/drivers/i2c/busses/i2c-coldfire.c b/drivers/i2c/busses/i2c-coldfire.c
new file mode 100644
index 0000000..97351c0
--- /dev/null
+++ b/drivers/i2c/busses/i2c-coldfire.c
@@ -0,0 +1,497 @@
+/* Freescale/Motorola Coldfire I2C driver.
+ *
+ * Copyright 2010, 2012 Steven King <sfking@fdwdc.com>
+ *
+ * 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 <linux/slab.h>
+#include <linux/pm_runtime.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;
+
+	u8			*buf;
+	u16			flags;
+	u16			len;
+	int			more;
+	int			status;
+};
+
+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);
+}
+
+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);
+}
+
+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);
+}
+
+static irqreturn_t mcfi2c_irq_handler(int this_irq, void *dev_id)
+{
+	struct mcfi2c *mcfi2c = dev_id;
+	u8 sr;
+
+	if (pm_runtime_suspended(&mcfi2c->adapter.dev))
+		return IRQ_NONE;
+
+	/* clear interrupt */
+	mcfi2c_wr_sr(mcfi2c, 0);
+
+	sr = mcfi2c_rd_sr(mcfi2c);
+	if (sr & MCFI2C_SR_IAL) {
+		mcfi2c_wr_sr(mcfi2c, ~MCFI2C_SR_IAL);
+		mcfi2c->status = -EIO;
+	} else if (mcfi2c_rd_cr(mcfi2c) & MCFI2C_CR_MTX) {
+		if (sr & MCFI2C_SR_RXAK) {
+			mcfi2c_stop(mcfi2c);
+			mcfi2c->status = -EIO;
+		} else if (mcfi2c->flags & I2C_M_RD) {
+			if (mcfi2c->len > 1)
+				mcfi2c_tx_ack(mcfi2c);
+			else
+				mcfi2c_tx_nak(mcfi2c);
+			/* dummy read */
+			mcfi2c_rd_dr(mcfi2c);
+			goto not_complete;
+
+		} else if (mcfi2c->len--) {
+			mcfi2c_wr_dr(mcfi2c, *(mcfi2c->buf++));
+			goto not_complete;
+		} else {
+			if (mcfi2c->more)
+				mcfi2c_repeat_start(mcfi2c);
+			else
+				mcfi2c_stop(mcfi2c);
+		}
+	} else if (--mcfi2c->len) {
+		if (!(mcfi2c->len > 1))
+			mcfi2c_tx_nak(mcfi2c);
+		*(mcfi2c->buf++) = mcfi2c_rd_dr(mcfi2c);
+		goto not_complete;
+	} else {
+		if (mcfi2c->more)
+			mcfi2c_repeat_start(mcfi2c);
+		else
+			mcfi2c_stop(mcfi2c);
+		*(mcfi2c->buf++) = mcfi2c_rd_dr(mcfi2c);
+	}
+	complete(&mcfi2c->completion);
+not_complete:
+	return IRQ_HANDLED;
+}
+
+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 int mcfi2c_wait_for_bus_idle(struct mcfi2c *mcfi2c)
+{
+	unsigned long timeout = jiffies + HZ / 2;
+	while (mcfi2c_rd_sr(mcfi2c) & MCFI2C_SR_IBB) {
+		if (time_after(jiffies, timeout))
+			return -EIO; /* bus is busy, try again */
+		cond_resched();
+	}
+	return 0;
+}
+
+static int mcfi2c_wait_for_bus_busy(struct mcfi2c *mcfi2c)
+{
+	unsigned long timeout = jiffies + HZ / 10;
+	u8 sr;
+	while (!((sr = mcfi2c_rd_sr(mcfi2c)) & MCFI2C_SR_IBB)) {
+		if (sr & MCFI2C_SR_IAL)
+			return -EIO; /* lost arbitration, try again */
+		if (time_after(jiffies, timeout)) {
+			/* if we dont get bus busy and dont get an arbitration
+			 * loss, then the bus is probably glitched, see if we
+			 * can recover.
+			*/
+			dev_dbg(&mcfi2c->adapter.dev,
+				"unable to send START, trying to reset the bus\n");
+			mcfi2c_reset(mcfi2c);
+			return -EIO;
+		}
+		cond_resched();
+	}
+	return 0;
+}
+
+static int mcfi2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
+		int num)
+{
+	struct mcfi2c *mcfi2c = i2c_get_adapdata(adapter);
+	int cnt = 0;
+
+	pm_runtime_get_sync(&adapter->dev);
+
+	while (num--) {
+		int retries = adapter->retries;
+		if (msgs->flags & ~I2C_M_RD) {
+			mcfi2c->status = -EINVAL;
+			goto done;
+		}
+		do {
+			mcfi2c->flags = msgs->flags;
+			mcfi2c->buf = msgs->buf;
+			mcfi2c->len = msgs->len;
+			mcfi2c->more = num;
+			mcfi2c->status = 0;
+
+			if (!(mcfi2c_rd_cr(mcfi2c) & MCFI2C_CR_MSTA)) {
+				mcfi2c->status =
+					       mcfi2c_wait_for_bus_idle(mcfi2c);
+				if (mcfi2c->status)
+					continue;
+
+				INIT_COMPLETION(mcfi2c->completion);
+				mcfi2c_start(mcfi2c);
+
+				mcfi2c->status =
+					       mcfi2c_wait_for_bus_busy(mcfi2c);
+				if (mcfi2c->status)
+					continue;
+			}
+
+			mcfi2c_wr_dr(mcfi2c, (msgs->addr << 1) |
+					(msgs->flags & I2C_M_RD));
+			if (!wait_for_completion_timeout(&mcfi2c->completion,
+						adapter->timeout * msgs->len)) {
+				mcfi2c->status = -ETIMEDOUT;
+				mcfi2c_stop(mcfi2c);
+			}
+
+		} while (mcfi2c->status && retries--);
+		if (mcfi2c->status)
+			goto done;
+		++cnt;
+		++msgs;
+	}
+done:
+	pm_runtime_put(&adapter->dev);
+
+	return mcfi2c->status ?: 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;
+	}
+
+	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, 0, pdev->name,
+			mcfi2c);
+	if (status) {
+		dev_dbg(&pdev->dev, "request_irq failed\n");
+		goto fail2;
+	}
+
+	mcfi2c->clk = clk_get(&pdev->dev, NULL);
+	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);
+
+	pm_runtime_enable(&pdev->dev);
+	pm_runtime_get_sync(&pdev->dev);
+
+	/* 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;
+	}
+
+	pm_runtime_put(&pdev->dev);
+
+	dev_info(&pdev->dev, "Coldfire I2C bus driver\n");
+
+	return 0;
+
+fail4:
+	pm_runtime_put(&pdev->dev);
+
+	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_RUNTIME
+static int mcfi2c_runtime_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_runtime_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;
+}
+#endif
+
+static const struct dev_pm_ops mcfi2c_pm = {
+	SET_RUNTIME_PM_OPS(mcfi2c_runtime_suspend, mcfi2c_runtime_resume, NULL)
+};
+
+static struct platform_driver mcfi2c_driver = {
+	.driver.name	= DRIVER_NAME,
+	.driver.owner	= THIS_MODULE,
+	.driver.pm	= &mcfi2c_pm,
+	.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 <sfking@fdwdc.com>");
+MODULE_DESCRIPTION("I2C-Bus support for Freescale Coldfire processors");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRIVER_NAME);

_______________________________________________
uClinux-dev mailing list
uClinux-dev@uclinux.org
http://mailman.uclinux.org/mailman/listinfo/uclinux-dev
This message was resent by uclinux-dev@uclinux.org
To unsubscribe see:
http://mailman.uclinux.org/mailman/options/uclinux-dev

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

* Re: [PATCH V3] m68knommu: driver for Freescale Coldfire I2C controller.
       [not found] ` <201205161910.36693.sfking-xS0NTnu2YfYAvxtiuMwx3w@public.gmane.org>
@ 2012-05-18  6:09   ` Greg Ungerer
  2012-06-11 17:46   ` Wolfram Sang
  1 sibling, 0 replies; 5+ messages in thread
From: Greg Ungerer @ 2012-05-18  6:09 UTC (permalink / raw)
  To: Steven King
  Cc: linux-i2c-u79uwXL29TY76Z2rM5mHXA, uClinux development list,
	gerg-JBU5SbJe1FlAfugRpC6u6w, Ben Dooks, Wolfram Sang

Hi Steven,

On 17/05/12 12:10, Steven King wrote:
> D'oh!  I really dropped the ball on this, but I figure better late than never ;-).
>
> Changes since V2:
>
> drivers/i2c/busses/i2c-coldfire.c:
> * As Ben suggested, making the interrupt handler do most of the message
>    processing and wake the thread when its done vastly improves performance.
> * preliminary support for PM_RUNTIME; but as there isn't arch support for for
>    PM_RUNTIME it doesn't do anything yet.
> * fixed a bug when the driver would hang on waiting for bus busy if the bus
>    never went busy.
>
> drivers/i2c/busses/Kconfig:
> * its easier to list the Coldfire MCUs that don't have I2C.
>
> arch/m68k/include/asm/mcfi2c.h:
> * moved the defines for the various Coldfire MCUs to the specific header
>     file for the various Coldfire MCUs.
>
>
> Support for the Freescale Coldfire I2C controller.
>
> Signed-off-by: Steven King<sfking-wDEDg+HZl8U@public.gmane.org>

Looks good to me.

Acked-by: Greg Ungerer <gerg-JBU5SbJe1FlAfugRpC6u6w@public.gmane.org>

Regards
Greg


> ---
>   arch/m68k/include/asm/mcfi2c.h    |   15 ++
>   drivers/i2c/busses/Kconfig        |   10 +
>   drivers/i2c/busses/Makefile       |    1 +
>   drivers/i2c/busses/i2c-coldfire.c |  497 +++++++++++++++++++++++++++++++++++++
>   4 files changed, 523 insertions(+)
>
> diff --git a/arch/m68k/include/asm/mcfi2c.h b/arch/m68k/include/asm/mcfi2c.h
> new file mode 100644
> index 0000000..24b0453
> --- /dev/null
> +++ b/arch/m68k/include/asm/mcfi2c.h
> @@ -0,0 +1,15 @@
> +/*
> + * Definitions for Coldfire I2C interface
> +*/
> +#ifndef mcfi2c_h
> +#define mcfi2c_h
> +
> +/**
> + * struct mcfi2c_platform_data - platform data for the coldfire i2c driver
> + * @bitrate: bitrate to use for this i2c controller.
> +*/
> +struct mcfi2c_platform_data {
> +	u32	bitrate;
> +};
> +
> +#endif /* mcfi2c_h */
> diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
> index d2c5095..159404e 100644
> --- a/drivers/i2c/busses/Kconfig
> +++ b/drivers/i2c/busses/Kconfig
> @@ -327,6 +327,16 @@ 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 !M5272
> +	help
> +	  This driver supports the I2C interface availible on most Freescale
> +	  Coldfire processors.
> +
> +	  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
> diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
> index 569567b..2c88c4a 100644
> --- a/drivers/i2c/busses/Makefile
> +++ b/drivers/i2c/busses/Makefile
> @@ -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_PLATFORM)	+= i2c-designware-platform.o
> diff --git a/drivers/i2c/busses/i2c-coldfire.c b/drivers/i2c/busses/i2c-coldfire.c
> new file mode 100644
> index 0000000..97351c0
> --- /dev/null
> +++ b/drivers/i2c/busses/i2c-coldfire.c
> @@ -0,0 +1,497 @@
> +/* Freescale/Motorola Coldfire I2C driver.
> + *
> + * Copyright 2010, 2012 Steven King<sfking-xS0NTnu2YfYAvxtiuMwx3w@public.gmane.org>
> + *
> + * 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<linux/slab.h>
> +#include<linux/pm_runtime.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;
> +
> +	u8			*buf;
> +	u16			flags;
> +	u16			len;
> +	int			more;
> +	int			status;
> +};
> +
> +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);
> +}
> +
> +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);
> +}
> +
> +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);
> +}
> +
> +static irqreturn_t mcfi2c_irq_handler(int this_irq, void *dev_id)
> +{
> +	struct mcfi2c *mcfi2c = dev_id;
> +	u8 sr;
> +
> +	if (pm_runtime_suspended(&mcfi2c->adapter.dev))
> +		return IRQ_NONE;
> +
> +	/* clear interrupt */
> +	mcfi2c_wr_sr(mcfi2c, 0);
> +
> +	sr = mcfi2c_rd_sr(mcfi2c);
> +	if (sr&  MCFI2C_SR_IAL) {
> +		mcfi2c_wr_sr(mcfi2c, ~MCFI2C_SR_IAL);
> +		mcfi2c->status = -EIO;
> +	} else if (mcfi2c_rd_cr(mcfi2c)&  MCFI2C_CR_MTX) {
> +		if (sr&  MCFI2C_SR_RXAK) {
> +			mcfi2c_stop(mcfi2c);
> +			mcfi2c->status = -EIO;
> +		} else if (mcfi2c->flags&  I2C_M_RD) {
> +			if (mcfi2c->len>  1)
> +				mcfi2c_tx_ack(mcfi2c);
> +			else
> +				mcfi2c_tx_nak(mcfi2c);
> +			/* dummy read */
> +			mcfi2c_rd_dr(mcfi2c);
> +			goto not_complete;
> +
> +		} else if (mcfi2c->len--) {
> +			mcfi2c_wr_dr(mcfi2c, *(mcfi2c->buf++));
> +			goto not_complete;
> +		} else {
> +			if (mcfi2c->more)
> +				mcfi2c_repeat_start(mcfi2c);
> +			else
> +				mcfi2c_stop(mcfi2c);
> +		}
> +	} else if (--mcfi2c->len) {
> +		if (!(mcfi2c->len>  1))
> +			mcfi2c_tx_nak(mcfi2c);
> +		*(mcfi2c->buf++) = mcfi2c_rd_dr(mcfi2c);
> +		goto not_complete;
> +	} else {
> +		if (mcfi2c->more)
> +			mcfi2c_repeat_start(mcfi2c);
> +		else
> +			mcfi2c_stop(mcfi2c);
> +		*(mcfi2c->buf++) = mcfi2c_rd_dr(mcfi2c);
> +	}
> +	complete(&mcfi2c->completion);
> +not_complete:
> +	return IRQ_HANDLED;
> +}
> +
> +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 int mcfi2c_wait_for_bus_idle(struct mcfi2c *mcfi2c)
> +{
> +	unsigned long timeout = jiffies + HZ / 2;
> +	while (mcfi2c_rd_sr(mcfi2c)&  MCFI2C_SR_IBB) {
> +		if (time_after(jiffies, timeout))
> +			return -EIO; /* bus is busy, try again */
> +		cond_resched();
> +	}
> +	return 0;
> +}
> +
> +static int mcfi2c_wait_for_bus_busy(struct mcfi2c *mcfi2c)
> +{
> +	unsigned long timeout = jiffies + HZ / 10;
> +	u8 sr;
> +	while (!((sr = mcfi2c_rd_sr(mcfi2c))&  MCFI2C_SR_IBB)) {
> +		if (sr&  MCFI2C_SR_IAL)
> +			return -EIO; /* lost arbitration, try again */
> +		if (time_after(jiffies, timeout)) {
> +			/* if we dont get bus busy and dont get an arbitration
> +			 * loss, then the bus is probably glitched, see if we
> +			 * can recover.
> +			*/
> +			dev_dbg(&mcfi2c->adapter.dev,
> +				"unable to send START, trying to reset the bus\n");
> +			mcfi2c_reset(mcfi2c);
> +			return -EIO;
> +		}
> +		cond_resched();
> +	}
> +	return 0;
> +}
> +
> +static int mcfi2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
> +		int num)
> +{
> +	struct mcfi2c *mcfi2c = i2c_get_adapdata(adapter);
> +	int cnt = 0;
> +
> +	pm_runtime_get_sync(&adapter->dev);
> +
> +	while (num--) {
> +		int retries = adapter->retries;
> +		if (msgs->flags&  ~I2C_M_RD) {
> +			mcfi2c->status = -EINVAL;
> +			goto done;
> +		}
> +		do {
> +			mcfi2c->flags = msgs->flags;
> +			mcfi2c->buf = msgs->buf;
> +			mcfi2c->len = msgs->len;
> +			mcfi2c->more = num;
> +			mcfi2c->status = 0;
> +
> +			if (!(mcfi2c_rd_cr(mcfi2c)&  MCFI2C_CR_MSTA)) {
> +				mcfi2c->status =
> +					       mcfi2c_wait_for_bus_idle(mcfi2c);
> +				if (mcfi2c->status)
> +					continue;
> +
> +				INIT_COMPLETION(mcfi2c->completion);
> +				mcfi2c_start(mcfi2c);
> +
> +				mcfi2c->status =
> +					       mcfi2c_wait_for_bus_busy(mcfi2c);
> +				if (mcfi2c->status)
> +					continue;
> +			}
> +
> +			mcfi2c_wr_dr(mcfi2c, (msgs->addr<<  1) |
> +					(msgs->flags&  I2C_M_RD));
> +			if (!wait_for_completion_timeout(&mcfi2c->completion,
> +						adapter->timeout * msgs->len)) {
> +				mcfi2c->status = -ETIMEDOUT;
> +				mcfi2c_stop(mcfi2c);
> +			}
> +
> +		} while (mcfi2c->status&&  retries--);
> +		if (mcfi2c->status)
> +			goto done;
> +		++cnt;
> +		++msgs;
> +	}
> +done:
> +	pm_runtime_put(&adapter->dev);
> +
> +	return mcfi2c->status ?: 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;
> +	}
> +
> +	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, 0, pdev->name,
> +			mcfi2c);
> +	if (status) {
> +		dev_dbg(&pdev->dev, "request_irq failed\n");
> +		goto fail2;
> +	}
> +
> +	mcfi2c->clk = clk_get(&pdev->dev, NULL);
> +	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);
> +
> +	pm_runtime_enable(&pdev->dev);
> +	pm_runtime_get_sync(&pdev->dev);
> +
> +	/* 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;
> +	}
> +
> +	pm_runtime_put(&pdev->dev);
> +
> +	dev_info(&pdev->dev, "Coldfire I2C bus driver\n");
> +
> +	return 0;
> +
> +fail4:
> +	pm_runtime_put(&pdev->dev);
> +
> +	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_RUNTIME
> +static int mcfi2c_runtime_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_runtime_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;
> +}
> +#endif
> +
> +static const struct dev_pm_ops mcfi2c_pm = {
> +	SET_RUNTIME_PM_OPS(mcfi2c_runtime_suspend, mcfi2c_runtime_resume, NULL)
> +};
> +
> +static struct platform_driver mcfi2c_driver = {
> +	.driver.name	= DRIVER_NAME,
> +	.driver.owner	= THIS_MODULE,
> +	.driver.pm	=&mcfi2c_pm,
> +	.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<sfking-xS0NTnu2YfYAvxtiuMwx3w@public.gmane.org>");
> +MODULE_DESCRIPTION("I2C-Bus support for Freescale Coldfire processors");
> +MODULE_LICENSE("GPL");
> +MODULE_ALIAS("platform:" DRIVER_NAME);
>
>
>
>


-- 
------------------------------------------------------------------------
Greg Ungerer  --  Principal Engineer        EMAIL:     gerg-XXXsiaCtIV5Wk0Htik3J/w@public.gmane.org
SnapGear Group, McAfee                      PHONE:       +61 7 3435 2888
8 Gardner Close                             FAX:         +61 7 3217 5323
Milton, QLD, 4064, Australia                WEB: http://www.SnapGear.com

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

* Re: [PATCH V3] m68knommu: driver for Freescale Coldfire I2C controller.
       [not found] ` <201205161910.36693.sfking-xS0NTnu2YfYAvxtiuMwx3w@public.gmane.org>
  2012-05-18  6:09   ` Greg Ungerer
@ 2012-06-11 17:46   ` Wolfram Sang
  2012-06-11 19:29     ` Steven King
  1 sibling, 1 reply; 5+ messages in thread
From: Wolfram Sang @ 2012-06-11 17:46 UTC (permalink / raw)
  To: Steven King
  Cc: linux-i2c-u79uwXL29TY76Z2rM5mHXA, uClinux development list,
	gerg-JBU5SbJe1FlAfugRpC6u6w, Ben Dooks

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

On Wed, May 16, 2012 at 07:10:35PM -0700, Steven King wrote:
> D'oh!  I really dropped the ball on this, but I figure better late than never ;-).

Thank you for this! Yet, I just noticed that the register layout is the
same as in i2c-imx.c. Not surprisingly, since both platforms share the
roots. Have you checked if you can use the imx-driver as well?

Regards,

   Wolfram

-- 
Pengutronix e.K.                           | Wolfram Sang                |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

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

* Re: [PATCH V3] m68knommu: driver for Freescale Coldfire I2C controller.
  2012-06-11 17:46   ` Wolfram Sang
@ 2012-06-11 19:29     ` Steven King
       [not found]       ` <201206111229.51887.sfking-xS0NTnu2YfYAvxtiuMwx3w@public.gmane.org>
  0 siblings, 1 reply; 5+ messages in thread
From: Steven King @ 2012-06-11 19:29 UTC (permalink / raw)
  To: Wolfram Sang; +Cc: gerg, linux-i2c, Ben Dooks, uClinux development list

On Monday 11 June 2012 10:46:34 am Wolfram Sang wrote:
> On Wed, May 16, 2012 at 07:10:35PM -0700, Steven King wrote:
> > D'oh!  I really dropped the ball on this, but I figure better late than
> > never ;-).
>
> Thank you for this! Yet, I just noticed that the register layout is the
> same as in i2c-imx.c. Not surprisingly, since both platforms share the
> roots. Have you checked if you can use the imx-driver as well?

While they are physically similar, just as the mpc and the imx are physically 
similar, the imx driver has a lot of imx'isms, device tree and OF 
dependencies that aren't supported by the m68k/nommu.  I would expect the 
changes needed tantamount to having separate drivers.  Plus I have no way of 
testing what impact any changes I made had on the imx functionality, so I 
expect I would end up mostly just annoying the imx developers.
_______________________________________________
uClinux-dev mailing list
uClinux-dev@uclinux.org
http://mailman.uclinux.org/mailman/listinfo/uclinux-dev
This message was resent by uclinux-dev@uclinux.org
To unsubscribe see:
http://mailman.uclinux.org/mailman/options/uclinux-dev

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

* Re: [PATCH V3] m68knommu: driver for Freescale Coldfire I2C controller.
       [not found]       ` <201206111229.51887.sfking-xS0NTnu2YfYAvxtiuMwx3w@public.gmane.org>
@ 2012-06-12  7:42         ` Wolfram Sang
  0 siblings, 0 replies; 5+ messages in thread
From: Wolfram Sang @ 2012-06-12  7:42 UTC (permalink / raw)
  To: Steven King
  Cc: linux-i2c-u79uwXL29TY76Z2rM5mHXA, uClinux development list,
	gerg-JBU5SbJe1FlAfugRpC6u6w, Ben Dooks

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

Hi,

> While they are physically similar, just as the mpc and the imx are physically 
> similar, the imx driver has a lot of imx'isms, device tree and OF 
> dependencies that aren't supported by the m68k/nommu.

Devicetree/OF should be optional. If not, we need to fix it anyhow. So,
the question is how much imx'ism there is really in there.

> I would expect the changes needed tantamount to having separate
> drivers.

If that is really true, then two seperate drivers might be the right
choice. Yet, I'd like to base this decision on facts and not
expectations (which might be wrong). I understand that you worked on the
driver for some time now, from a maintanence point of view having only
one driver is preferable, though. That works at least for fec.c.

>  Plus I have no way of testing what impact any changes I made had on
>  the imx functionality, so I expect I would end up mostly just
>  annoying the imx developers.

I am an imx-developer and I won't be annoyed :)

Thanks,

   Wolfram

-- 
Pengutronix e.K.                           | Wolfram Sang                |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

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

end of thread, other threads:[~2012-06-12  7:42 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-05-17  2:10 [PATCH V3] m68knommu: driver for Freescale Coldfire I2C controller Steven King
     [not found] ` <201205161910.36693.sfking-xS0NTnu2YfYAvxtiuMwx3w@public.gmane.org>
2012-05-18  6:09   ` Greg Ungerer
2012-06-11 17:46   ` Wolfram Sang
2012-06-11 19:29     ` Steven King
     [not found]       ` <201206111229.51887.sfking-xS0NTnu2YfYAvxtiuMwx3w@public.gmane.org>
2012-06-12  7:42         ` Wolfram Sang

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