linux-i2c.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Ben Dooks <ben-linux-elnMNo+KYs3YtjvyW6yDsg@public.gmane.org>
To: dmitry pervushin
	<dpervushin-L1vi/lXTdtvkgf6YlCu6wwC/G2K4zDHf@public.gmane.org>
Cc: Ben Dooks <ben-linux-elnMNo+KYs3YtjvyW6yDsg@public.gmane.org>,
	linux-i2c-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
Subject: Re: [PATCH, RFC] Freescale STMP: i2c driver
Date: Mon, 22 Jun 2009 01:47:41 +0100	[thread overview]
Message-ID: <20090622004741.GB9006@fluff.org.uk> (raw)
In-Reply-To: <1245169913.32549.19.camel-GL0tbJR47UuzLY3athcO2A@public.gmane.org>

On Tue, Jun 16, 2009 at 08:31:53PM +0400, dmitry pervushin wrote:
> On Mon, 2009-06-15 at 09:19 +0100, Ben Dooks wrote:
> > any chance of an reply or update driver for inclusion?
> Here it is:
>
> From: Dmitrij Frasenyak <d.frasenyak-L1vi/lXTdtvkgf6YlCu6wwC/G2K4zDHf@public.gmane.org>
> Signed-off-by: dmitry pervushin <dpervushin-L1vi/lXTdtvkgf6YlCu6wwC/G2K4zDHf@public.gmane.org>
> 
> Add I2C driver for Freescale STMP boards

Sorry, forgot to come back and sort this one out.

The From: field is fine, but the first signed-off-by should also be
from Dimirij as well (to say that as the creator he is accepting that
this is suitable for inclusion - I do hope you've both read at-least
section 12 of Documentation/SubmittingPatches).

The signed-off-by should go after the description text, and must have
Dimirij's Signed-off-By, and it would be nice to have yours in there
too.
 
> ---
>  drivers/i2c/busses/Kconfig        |    7 
>  drivers/i2c/busses/Makefile       |    1 
>  drivers/i2c/busses/i2c-stmp378x.c |  448 ++++++++++++++++++++++++++++++++++++++
>  3 files changed, 456 insertions(+)
> 
> Index: linux-2.6-arm/drivers/i2c/busses/Kconfig
> ===================================================================
> --- linux-2.6-arm.orig/drivers/i2c/busses/Kconfig
> +++ linux-2.6-arm/drivers/i2c/busses/Kconfig
> @@ -513,6 +513,13 @@ config I2C_SIMTEC
>  	  This driver can also be built as a module. If so, the module
>  	  will be called i2c-simtec.
>  
> +config I2C_STMP378X
> +	tristate "STMP378x I2C adapter"
> +	depends on ARCH_STMP378X
> +	help
> +	  Include support of I2C adapter on Freescale STMP378x board; to build
> +	  the driver as a module, say M here - module will be called i2c-stmp378x.
> +
>  config I2C_VERSATILE
>  	tristate "ARM Versatile/Realview I2C bus support"
>  	depends on ARCH_VERSATILE || ARCH_REALVIEW
> Index: linux-2.6-arm/drivers/i2c/busses/Makefile
> ===================================================================
> --- linux-2.6-arm.orig/drivers/i2c/busses/Makefile
> +++ linux-2.6-arm/drivers/i2c/busses/Makefile
> @@ -48,6 +48,7 @@ obj-$(CONFIG_I2C_S6000)		+= i2c-s6000.o
>  obj-$(CONFIG_I2C_SH7760)	+= i2c-sh7760.o
>  obj-$(CONFIG_I2C_SH_MOBILE)	+= i2c-sh_mobile.o
>  obj-$(CONFIG_I2C_SIMTEC)	+= i2c-simtec.o
> +obj-$(CONFIG_I2C_STMP378X)	+= i2c-stmp378x.o
>  obj-$(CONFIG_I2C_VERSATILE)	+= i2c-versatile.o
>  
>  # External I2C/SMBus adapter drivers
> Index: linux-2.6-arm/drivers/i2c/busses/i2c-stmp378x.c
> ===================================================================
> --- /dev/null
> +++ linux-2.6-arm/drivers/i2c/busses/i2c-stmp378x.c
> @@ -0,0 +1,448 @@
> +/*
> + * Freescale STMP378X I2C bus driver
> + *
> + * Author: Dmitrij Frasenyak <sed-L1vi/lXTdtvkgf6YlCu6wwC/G2K4zDHf@public.gmane.org>
> + *
> + * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
> + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
> + */
> +
> +/*
> + * The code contained herein is licensed under the GNU General Public
> + * License. You may obtain a copy of the GNU General Public License
> + * Version 2 or later at the following locations:
> + *
> + * http://www.opensource.org/licenses/gpl-license.html
> + * http://www.gnu.org/copyleft/gpl.html
> + */
> +#include <linux/module.h>
> +#include <linux/delay.h>
> +#include <linux/i2c.h>
> +#include <linux/err.h>
> +#include <linux/interrupt.h>
> +#include <linux/completion.h>
> +#include <linux/platform_device.h>
> +#include <linux/clk.h>
> +#include <linux/io.h>
> +#include <linux/dma-mapping.h>
> +
> +#include <mach/platform.h>
> +#include <mach/stmp3xxx.h>
> +#include <mach/dma.h>
> +#include <mach/regs-i2c.h>
> +#include <mach/regs-apbx.h>
> +
> +static const struct stmp3xxx_dma_command cmd_i2c_select = {
> +	.cmd =	BF(1, APBX_CHn_CMD_XFER_COUNT)	|
> +		BF(1, APBX_CHn_CMD_CMDWORDS)	|
> +		BM_APBX_CHn_CMD_WAIT4ENDCMD	|
> +		BM_APBX_CHn_CMD_CHAIN		|
> +		BF(BV_APBX_CHn_CMD_COMMAND__DMA_READ, APBX_CHn_CMD_COMMAND),
> +	.pio_words = {
> +		[0] = 	BM_I2C_CTRL0_RETAIN_CLOCK   |
> +			BM_I2C_CTRL0_PRE_SEND_START |
> +			BM_I2C_CTRL0_MASTER_MODE    |
> +			BM_I2C_CTRL0_DIRECTION      |
> +			BF(1, I2C_CTRL0_XFER_COUNT),
> +	},
> +};
> +
> +static const struct stmp3xxx_dma_command cmd_i2c_write = {
> +	.cmd =	BM_APBX_CHn_CMD_SEMAPHORE	|
> +		BF(1, APBX_CHn_CMD_CMDWORDS)	|
> +		BM_APBX_CHn_CMD_WAIT4ENDCMD	|
> +		BM_APBX_CHn_CMD_IRQONCMPLT	|
> +		BF(BV_APBX_CHn_CMD_COMMAND__DMA_READ, APBX_CHn_CMD_COMMAND),
> +	.pio_words = {
> +		[0] =	BM_I2C_CTRL0_PRE_SEND_START |
> +			BM_I2C_CTRL0_MASTER_MODE    |
> +			BM_I2C_CTRL0_DIRECTION,
> +	},
> +};
> +
> +static const struct stmp3xxx_dma_command cmd_i2c_read = {
> +	.cmd =	BM_APBX_CHn_CMD_SEMAPHORE	|
> +		BF(1, APBX_CHn_CMD_CMDWORDS)	|
> +		BM_APBX_CHn_CMD_WAIT4ENDCMD	|
> +		BM_APBX_CHn_CMD_IRQONCMPLT	|
> +		BF(BV_APBX_CHn_CMD_COMMAND__DMA_WRITE, APBX_CHn_CMD_COMMAND),
> +	.pio_words = {
> +		[0] =	BM_I2C_CTRL0_SEND_NAK_ON_LAST	|
> +			BM_I2C_CTRL0_MASTER_MODE,
> +	},
> +};
> +
> +/**
> + * struct stmp378x_i2c_dev - STMP3xxx I2C adapter data
> + * @dev: the associated platform_device
> + * @cmd_complete: the completion structure indicating that message has been
> + * 	transferred
> + * @cmd_err: current error code
> + * @adapter: the adapter we implement
> + * @io: io address
> + * @irq: irq number
> + * @dma: dma channel
> + * @bufv: pointer to the dma buffer
> + * @bufp: physical address of the dma buffer
> + * @i2c_dma_read: "read" dma chain (read request and then write)
> + * @i2c_dma_write: "write" dma chain (the single combined write request)
> + */
> +struct stmp378x_i2c_dev {
> +	struct device		*dev;
> +	int			irq;
> +	struct completion	cmd_complete;
> +	u32			cmd_err;
> +	struct i2c_adapter	adapter;
> +	void __iomem 		*io;
> +	unsigned		dma;
> +
> +	dma_addr_t		bufp;
> +	unsigned char		*bufv;
> +
> +	struct stmp3xxx_dma_descriptor i2c_dma_read[2],
> +				       i2c_dma_write;
> +};
> +
> +static int stmp378x_i2c_init(struct stmp378x_i2c_dev *dev)
> +{
> +	int err;
> +
> +	err = stmp3xxx_dma_request(dev->dma, dev->dev, dev_name(dev->dev));
> +	if (err)
> +		goto out;
> +	stmp3xxx_reset_block(dev->io, true);
> +
> +	dev->bufv = dma_alloc_coherent(dev->dev, PAGE_SIZE,
> +				       &dev->bufp, GFP_KERNEL);
> +	if (!dev->bufv)
> +		goto out_dma;
> +
> +	err = stmp3xxx_request_pin_group(dev->dev->platform_data,
> +			dev_name(dev->dev));
> +	if (err)
> +		goto out_free;
> +
> +	err = stmp3xxx_dma_allocate_command(dev->dma, &dev->i2c_dma_read[0]);
> +	if (err)
> +		goto out_rd0;
> +	err = stmp3xxx_dma_allocate_command(dev->dma, &dev->i2c_dma_read[1]);
> +	if (err)
> +		goto out_rd1;
> +	err = stmp3xxx_dma_allocate_command(dev->dma, &dev->i2c_dma_write);
> +	if (err)
> +		goto out_wr;
> +
> +	stmp3xxx_dma_reset_channel(dev->dma);
> +	stmp3xxx_dma_clear_interrupt(dev->dma);
> +	stmp3xxx_dma_enable_interrupt(dev->dma);
> +
> +	return 0;
> +/*
> +	stmp3xxx_dma_free_command(dev->dma, &dev->i2c_dma_write);
> +*/
> +out_wr:
> +	stmp3xxx_dma_free_command(dev->dma, &dev->i2c_dma_read[1]);
> +out_rd1:
> +	stmp3xxx_dma_free_command(dev->dma, &dev->i2c_dma_read[0]);
> +out_rd0:
> +	stmp3xxx_release_pin_group(dev->dev->platform_data, dev_name(dev->dev));
> +out_free:
> +	dma_free_coherent(dev->dev, PAGE_SIZE, dev->bufv, dev->bufp);
> +out_dma:
> +	stmp3xxx_dma_release(dev->dma);
> +out:
> +	return err;
> +}
> +
> +static void stmp378x_i2c_release(struct stmp378x_i2c_dev *dev)
> +{
> +	stmp3xxx_dma_free_command(dev->dma, &dev->i2c_dma_write);
> +	stmp3xxx_dma_free_command(dev->dma, &dev->i2c_dma_read[1]);
> +	stmp3xxx_dma_free_command(dev->dma, &dev->i2c_dma_read[0]);
> +	dma_free_coherent(dev->dev, PAGE_SIZE, dev->bufv, dev->bufp);
> +	stmp3xxx_release_pin_group(dev->dev->platform_data, dev_name(dev->dev));
> +	stmp3xxx_dma_release(dev->dma);
> +}
> +/*
> + * Low level master read/write transaction.
> + */
> +static int stmp378x_i2c_xfer_msg(struct i2c_adapter *adap,
> +				 struct i2c_msg *msg, int stop)
> +{
> +	struct stmp378x_i2c_dev *dev = i2c_get_adapdata(adap);
> +	int err;
> +	struct stmp3xxx_dma_descriptor *c, *r;
> +
> +	init_completion(&dev->cmd_complete);
> +	dev->cmd_err = 0;
> +
> +	if ((msg->len == 0) || (msg->len > (PAGE_SIZE - 1)))
> +		return -EINVAL;
> +
> +	if (msg->flags & I2C_M_RD) {
> +
> +		c = &dev->i2c_dma_read[0];
> +		r = &dev->i2c_dma_read[1];
> +
> +		/* first, setup the SELECT command */
> +		memcpy(c->command, &cmd_i2c_select, sizeof(cmd_i2c_select));
> +		c->command->buf_ptr = dev->bufp;
> +		dev->bufv[0] = msg->addr | I2C_SMBUS_READ;
> +
> +		/* then, setup the READ command */
> +		memcpy(r->command, &cmd_i2c_read, sizeof(cmd_i2c_read));
> +		r->command->cmd |= BF(msg->len, APBX_CHn_CMD_XFER_COUNT);
> +		r->command->pio_words[0] |= BF(msg->len, I2C_CTRL0_XFER_COUNT);
> +		if (stop)
> +			r->command->pio_words[0] |= BM_I2C_CTRL0_POST_SEND_STOP;
> +		/*
> +		 * yes, STMP controller can DMA transfer the data from any
> +		 * byte boundary
> +		 */
> +		r->command->buf_ptr = dev->bufp + 1;
> +
> +		/* and chain them together */
> +		c->command->next = r->handle;
> +
> +	} else {
> +
> +		c = &dev->i2c_dma_write;
> +		memcpy(c->command, &cmd_i2c_write, sizeof(cmd_i2c_write));
> +		c->command->cmd |= BF(msg->len + 1, APBX_CHn_CMD_XFER_COUNT);
> +		c->command->pio_words[0] |=
> +				   BF(msg->len + 1, I2C_CTRL0_XFER_COUNT);
> +		if (stop)
> +			c->command->pio_words[0] |=
> +				   BM_I2C_CTRL0_POST_SEND_STOP;
> +		dev->bufv[0] = msg->addr | I2C_SMBUS_WRITE;
> +		memcpy(dev->bufv + 1, msg->buf, msg->len);
> +	}
> +
> +	stmp3xxx_dma_go(dev->dma, c, 1);
> +
> +	err = wait_for_completion_interruptible_timeout(&dev->cmd_complete,
> +							msecs_to_jiffies(1000));
> +
> +	if (err < 0) {
> +		dev_dbg(dev->dev, "controler is timed out\n");
> +		return -ETIMEDOUT;
> +	}
> +	if (!dev->cmd_err && (msg->flags & I2C_M_RD))
> +		memcpy(msg->buf, dev->bufv + 1, msg->len);
> +
> +	dev_dbg(dev->dev, "done with err=%d\n", dev->cmd_err);
> +
> +	return dev->cmd_err;
> +}
> +
> +
> +static int
> +stmp378x_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
> +{
> +	int i;
> +	int err;
> +
> +	if (!msgs->len)
> +		return -EINVAL;
> +
> +	for (i = 0; i < num; i++) {
> +		err = stmp378x_i2c_xfer_msg(adap, &msgs[i], (i == (num - 1)));
> +		if (err)
> +			return err;
> +	}
> +	return num;
> +}
> +
> +static u32
> +stmp378x_i2c_func(struct i2c_adapter *adap)
> +{
> +	return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);
> +}
> +
> +#define I2C_IRQ_MASK 0x000000FF
> +static irqreturn_t
> +stmp378x_i2c_isr(int this_irq, void *dev_id)
> +{
> +	struct stmp378x_i2c_dev *dev = dev_id;
> +	u32 stat;
> +	u32 done_mask = BM_I2C_CTRL1_DATA_ENGINE_CMPLT_IRQ |
> +			BM_I2C_CTRL1_BUS_FREE_IRQ ;
> +
> +	stat = readl(HW_I2C_CTRL1 + dev->io) & I2C_IRQ_MASK;
> +	if (!stat)
> +		return IRQ_NONE;
> +
> +	if (stat & BM_I2C_CTRL1_NO_SLAVE_ACK_IRQ) {
> +		dev->cmd_err = -EREMOTEIO;
> +
> +		/*
> +		 * Stop DMA
> +		 * Clear NAK
> +		 */
> +		stmp3xxx_setl(BM_I2C_CTRL1_CLR_GOT_A_NAK,
> +			      HW_I2C_CTRL1 + dev->io);
> +		stmp3xxx_dma_reset_channel(dev->dma);
> +		stmp3xxx_dma_clear_interrupt(dev->dma);
> +
> +		complete(&dev->cmd_complete);
> +
> +		goto done;
> +	}
> +
> +	/* Don't care about  BM_I2C_CTRL1_OVERSIZE_XFER_TERM_IRQ */
> +	if (stat & (BM_I2C_CTRL1_EARLY_TERM_IRQ |
> +		    BM_I2C_CTRL1_MASTER_LOSS_IRQ |
> +		    BM_I2C_CTRL1_SLAVE_STOP_IRQ |
> +		    BM_I2C_CTRL1_SLAVE_IRQ)) {
> +		dev->cmd_err = -EIO;
> +		complete(&dev->cmd_complete);
> +		goto done;
> +	}
> +
> +	if ((stat & done_mask) == done_mask)
> +		complete(&dev->cmd_complete);
> +
> +done:
> +	stmp3xxx_clearl(stat, dev->io + HW_I2C_CTRL1);
> +	return IRQ_HANDLED;
> +}
> +
> +static const struct i2c_algorithm stmp378x_i2c_algo = {
> +	.master_xfer	= stmp378x_i2c_xfer,
> +	.functionality	= stmp378x_i2c_func,
> +};
> +
> +
> +static int __devinit
> +stmp378x_i2c_probe(struct platform_device *pdev)
> +{
> +	struct stmp378x_i2c_dev	*dev;
> +	struct i2c_adapter	*adap;
> +	struct resource		*mem, *dma;
> +	int err = 0;
> +
> +	dev = kzalloc(sizeof(struct stmp378x_i2c_dev), GFP_KERNEL);
> +	if (!dev) {
> +		dev_err(&pdev->dev, "no mem \n");
> +		return -ENOMEM;
> +	}
> +
> +	dev->irq = platform_get_irq(pdev, 0); /* Error */
> +	if (dev->irq < 0) {
> +		dev_err(&pdev->dev, "no err_irq resource\n");
> +		err = dev->irq;
> +		goto nores;
> +	}
> +
> +	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	if (!mem) {
> +		dev_err(&pdev->dev, "no memory window\n");
> +		err = -ENODEV;
> +		goto nores;
> +	}
> +
> +	dma = platform_get_resource(pdev, IORESOURCE_DMA, 0);
> +	if (!dma) {
> +		dev_err(&pdev->dev, "no dma channel\n");
> +		err = -ENODEV;
> +		goto nores;
> +	}
> +	dev->dma = dma->start;
> +
> +	dev->dev = &pdev->dev;
> +	dev->io = ioremap(mem->start, resource_size(mem));
> +	if (!dev->io) {
> +		dev_err(&pdev->dev, "cannot ioremap\n");
> +		err = -ENXIO;
> +		goto nores;
> +	}
> +
> +	err = request_irq(dev->irq, stmp378x_i2c_isr, 0, pdev->name, dev);
> +	if (err) {
> +		dev_err(&pdev->dev, "Can't get IRQ\n");
> +		goto no_err_irq;
> +	}
> +
> +	err = stmp378x_i2c_init(dev);
> +	if (err) {
> +		dev_err(&pdev->dev, "HW Init failed\n");
> +		goto init_failed;
> +	}
> +
> +	stmp3xxx_setl(0xFF00, dev->io + HW_I2C_CTRL1);
> +
> +	adap = &dev->adapter;
> +	i2c_set_adapdata(adap, dev);
> +	adap->owner = THIS_MODULE;
> +	adap->class = I2C_CLASS_TV_DIGITAL;
> +	strncpy(adap->name, "378x I2C adapter", sizeof(adap->name));
> +	adap->algo = &stmp378x_i2c_algo;
> +	adap->dev.parent = &pdev->dev;
> +
> +	adap->nr = pdev->id;
> +	err = i2c_add_numbered_adapter(adap);
> +	if (err) {
> +		dev_err(&pdev->dev, "Failed to add adapter\n");
> +		goto no_i2c_adapter;
> +
> +	}
> +
> +	return 0;
> +
> +no_i2c_adapter:
> +	stmp378x_i2c_release(dev);
> +init_failed:
> +	free_irq(dev->irq, dev);
> +no_err_irq:
> +	iounmap(dev->io);
> +nores:
> +	kfree(dev);
> +	return err;
> +}
> +
> +static int __devexit
> +stmp378x_i2c_remove(struct platform_device *pdev)
> +{
> +	struct stmp378x_i2c_dev	*dev = platform_get_drvdata(pdev);
> +	int res;
> +
> +	res = i2c_del_adapter(&dev->adapter);
> +	if (res)
> +		return -EBUSY;
> +
> +	stmp378x_i2c_release(dev);
> +
> +	platform_set_drvdata(pdev, NULL);
> +
> +	free_irq(dev->irq, dev);
> +	iounmap(dev->io);
> +
> +	kfree(dev);
> +	return 0;
> +}
> +
> +static struct platform_driver stmp378x_i2c_driver = {
> +	.probe		= stmp378x_i2c_probe,
> +	.remove		= __devexit_p(stmp378x_i2c_remove),
> +	.driver		= {
> +		.name	= "i2c_stmp3xxx",
> +		.owner	= THIS_MODULE,
> +	},
> +};
> +
> +static int __init stmp378x_i2c_init_driver(void)
> +{
> +	return platform_driver_register(&stmp378x_i2c_driver);
> +}
> +module_init(stmp378x_i2c_init_driver);
> +
> +static void __exit stmp378x_i2c_exit_driver(void)
> +{
> +	platform_driver_unregister(&stmp378x_i2c_driver);
> +}
> +module_exit(stmp378x_i2c_exit_driver);
> +
> +MODULE_AUTHOR("d.frasenyak-L1vi/lXTdtvkgf6YlCu6wwC/G2K4zDHf@public.gmane.org");
> +MODULE_DESCRIPTION("I2C for Freescale STMP378x");
> +MODULE_LICENSE("GPL");
> +MODULE_ALIAS("platform:i2c_stmp3xxx");
> 
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-i2c" in
> the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

-- 
Ben (ben-elnMNo+KYs3YtjvyW6yDsg@public.gmane.org, http://www.fluff.org/)

  'a smiley only costs 4 bytes'

  parent reply	other threads:[~2009-06-22  0:47 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-06-03 19:59 [PATCH, RFC] Freescale STMP: i2c driver dmitry pervushin
     [not found] ` <1244059155.4074.19.camel-GL0tbJR47UuzLY3athcO2A@public.gmane.org>
2009-06-08 22:50   ` Ben Dooks
     [not found]     ` <20090608225034.GA20446-elnMNo+KYs3pIgCt6eIbzw@public.gmane.org>
2009-06-09  7:46       ` Jean Delvare
2009-06-16 16:25       ` dmitry pervushin
     [not found]         ` <1245169539.32549.12.camel-GL0tbJR47UuzLY3athcO2A@public.gmane.org>
2009-06-22 10:51           ` Ben Dooks
     [not found]             ` <20090622105148.GC9006-elnMNo+KYs3pIgCt6eIbzw@public.gmane.org>
2009-06-22 13:41               ` dmitry pervushin
2009-06-15  8:19   ` Ben Dooks
     [not found]     ` <20090615081938.GA19878-elnMNo+KYs3pIgCt6eIbzw@public.gmane.org>
2009-06-16 16:31       ` dmitry pervushin
     [not found]         ` <1245169913.32549.19.camel-GL0tbJR47UuzLY3athcO2A@public.gmane.org>
2009-06-22  0:47           ` Ben Dooks [this message]
     [not found]             ` <20090622004741.GB9006-elnMNo+KYs3pIgCt6eIbzw@public.gmane.org>
2009-06-22 13:39               ` dmitry pervushin
2009-06-22 13:42               ` [PATCH, RFC] Freescale STMP: i2c driver, updated with correct signed-off lines dmitry pervushin

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20090622004741.GB9006@fluff.org.uk \
    --to=ben-linux-elnmno+kys3ytjvyw6ydsg@public.gmane.org \
    --cc=dpervushin-L1vi/lXTdtvkgf6YlCu6wwC/G2K4zDHf@public.gmane.org \
    --cc=linux-i2c-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).