* [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
[parent not found: <201205161910.36693.sfking-xS0NTnu2YfYAvxtiuMwx3w@public.gmane.org>]
* 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
[parent not found: <201206111229.51887.sfking-xS0NTnu2YfYAvxtiuMwx3w@public.gmane.org>]
* 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).