All of lore.kernel.org
 help / color / mirror / Atom feed
From: Wolfram Sang <wsa@the-dreams.de>
To: Naveen Krishna Chatradhi <ch.naveen@samsung.com>
Cc: linux-i2c@vger.kernel.org, linux-kernel@vger.kernel.org,
	linux-samsung-soc@vger.kernel.org, w.sang@pengutronix.de,
	t.figa@samsung.com, ben-linux@fluff.org,
	grant.likely@secretlab.ca, devicetree-discuss@lists.ozlabs.org,
	sjg@chromium.org, naveenkrishna.ch@gmail.com,
	broonie@opensource.wolfsonmicro.com
Subject: Re: [PATCH] i2c: exynos5: add High Speed I2C controller driver
Date: Sun, 8 Sep 2013 19:03:56 +0200	[thread overview]
Message-ID: <20130908170355.GA3154@katana> (raw)
In-Reply-To: <1377077077-20896-1-git-send-email-ch.naveen@samsung.com>

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


On Wed, Aug 21, 2013 at 02:54:37PM +0530, Naveen Krishna Ch wrote:
> Adds support for High Speed I2C driver found in Exynos5 and
> later SoCs from Samsung.
> 
> Highspeed mode is a minor change in the i2c protocol.
> Starts with
> 1. start condition,
> 2. 8-bit master ID code (00001xxx)
> 3. followed by a NACK bit
> Once the above conditions are met, the bus is now operates in highspeed mode.
> The rest of the I2C protocol applies the same.

The description is correct, but it is not a change in the protocol. This
is fully specified in the I2C specs.

> Driver only supports Device Tree method.
> 
> Changes since v1:
> 1. Added FIFO functionality
> 2. Added High speed mode functionality
> 3. Remove SMBUS_QUICK
> 4. Remove the debugfs functionality
> 5. Use devm_* functions where ever possible
> 6. Driver is free from GPIO configs
> 7. Use OF data string "clock-frequency" to get the bus operating frequencies
> 8. Split the clock divisor calculation function
> 9. Add resets for the failed transacton cases
> 10. Removed retries as core does retries if -EAGAIN is returned
> 11. Removed mode from device tree info (use speed to distinguish
>     the mode of operation)
> 12. Use wait_for_completion_timeout as the interruptible case is not tested well
> 13. few other bug fixes and cosmetic changes
> 14. Removed the untested runtime_pm code
> 15. Removed the retries as core does that
> 16. Use adap.nr instead of alias
> 17. Added spinlocks around the irq code
> 18. Use i2c_add_numbered_adapter() instead of using aliases

Changes since v1 are irrelevant for the patch description.

> 
> Signed-off-by: Taekgyun Ko <taeggyun.ko@samsung.com>
> Signed-off-by: Naveen Krishna Chatradhi <ch.naveen@samsung.com>
> Reviewed-by: Simon Glass <sjg@google.com>
> Tested-by: Andrew Bresticker <abrestic@google.com>
> Signed-off-by: Yuvaraj Kumar C D <yuvaraj.cd@samsung.com>
> Signed-off-by: Andrew Bresticker <abrestic@google.com>
> 
> ---
> Wolfram and Thomas Figa thanks for reviewing the code.
> 
> Changes since v10:
> 1. Remove the incomplete runtime_pm code
> 2. Correct the error checks as suggested by Thomas
> 3. Use i2c_add_numbered_adapter() as suggested
> 4. Modified the irq routine to handle the specific interrupts
> 5. Added spinlocks around the irq code
> 6. Remove the "mode" of operation field from device tree node and use the
>    clock-frequency to decide the mode.
> 
>  .../devicetree/bindings/i2c/i2c-exynos5.txt        |   44 ++
>  drivers/i2c/busses/Kconfig                         |    7 +
>  drivers/i2c/busses/Makefile                        |    1 +
>  drivers/i2c/busses/i2c-exynos5.c                   |  799 ++++++++++++++++++++
>  4 files changed, 851 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/i2c/i2c-exynos5.txt
>  create mode 100644 drivers/i2c/busses/i2c-exynos5.c
> 
> diff --git a/Documentation/devicetree/bindings/i2c/i2c-exynos5.txt b/Documentation/devicetree/bindings/i2c/i2c-exynos5.txt
> new file mode 100644
> index 0000000..805e018
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/i2c/i2c-exynos5.txt
> @@ -0,0 +1,44 @@
> +* Samsung's High Speed I2C controller
> +
> +The Samsung's High Speed I2C controller is used to interface with I2C devices
> +at various speeds ranging from 100khz to 3.4Mhz.
> +
> +Required properties:
> +  - compatible: value should be.
> +      -> "samsung,exynos5-hsi2c", for i2c compatible with exynos5 hsi2c.
> +  - reg: physical base address of the controller and length of memory mapped
> +    region.
> +  - interrupts: interrupt number to the cpu.
> +  - #address-cells: always 1 (for i2c addresses)
> +  - #size-cells: always 0
> +
> +  - Pinctrl:
> +    - pinctrl-0: Pin control group to be used for this controller.
> +    - pinctrl-names: Should contain only one value - "default".
> +
> +Optional properties:
> +  - clock-frequency: Desired operating frequency in Hz of the bus.
> +    -> If not specified, the default value is 100khz in fast-speed mode and
> +       1Mhz in high-speed mode.

Description doesn't match the current code.

> +    -> If specified, The bus operates in high-speed mode only if the
> +       clock-frequency is >= 1Mhz.

s/The/the/

...

> +/*
> + * exynos5_i2c_init: configures the controller for I2C functionality
> + * Programs I2C controller for Master mode operation
> + */
> +static void exynos5_i2c_init(struct exynos5_i2c *i2c)
> +{
> +	u32 i2c_conf = readl(i2c->regs + HSI2C_CONF);
> +	u32 i2c_timeout = readl(i2c->regs + HSI2C_TIMEOUT);
> +
> +	/* Disable timeout */
> +	i2c_timeout &= ~HSI2C_TIMEOUT_EN;
> +	writel(i2c_timeout, i2c->regs + HSI2C_TIMEOUT);

Just curious: Can't you use HSI2C_TIMEOUT and wait_for_completion
instead of wait_for_completion_timeout? If so, it might save you a
little bit of overhead.

> +
> +	writel((HSI2C_FUNC_MODE_I2C | HSI2C_MASTER),
> +					i2c->regs + HSI2C_CTL);
> +	writel(HSI2C_TRAILING_COUNT, i2c->regs + HSI2C_TRAILIG_CTL);
> +
> +	if (i2c->speed_mode == HSI2C_HIGH_SPD) {
> +		writel(HSI2C_MASTER_ID(MASTER_ID(i2c->adap.nr)),
> +					i2c->regs + HSI2C_ADDR);
> +		i2c_conf |= HSI2C_HS_MODE;
> +	}
> +
> +	writel(i2c_conf | HSI2C_AUTO_MODE, i2c->regs + HSI2C_CONF);
> +}
> +
> +
> +	if ((i2c->msg->flags & I2C_M_RD) && (int_status &
> +			(HSI2C_INT_TRAILING | HSI2C_INT_RX_ALMOSTFULL))) {
> +		fifo_status = readl(i2c->regs + HSI2C_FIFO_STATUS);
> +		fifo_level = HSI2C_RX_FIFO_LVL(fifo_status);
> +		len = min(fifo_level, i2c->msg->len - i2c->msg_ptr);
> +
> +		while (len > 0) {
> +			byte = (unsigned char)
> +				readl(i2c->regs + HSI2C_RX_DATA);
> +			i2c->msg->buf[i2c->msg_ptr++] = byte;
> +			len--;
> +		}

With all this copying going on, this should be threaded irq probably.

> +		i2c->state = 0;
> +	} else if (int_status & HSI2C_INT_TX_ALMOSTEMPTY) {
> +		fifo_status = readl(i2c->regs + HSI2C_FIFO_STATUS);
> +		fifo_level = HSI2C_TX_FIFO_LVL(fifo_status);
> +
> +		len = HSI2C_FIFO_MAX - fifo_level;
> +		if (len > (i2c->msg->len - i2c->msg_ptr))
> +			len = i2c->msg->len - i2c->msg_ptr;
> +
> +		while (len > 0) {
> +			byte = i2c->msg->buf[i2c->msg_ptr++];
> +			writel(byte, i2c->regs + HSI2C_TX_DATA);
> +			len--;
> +		}
> +		i2c->state = 0;
> +	}
> +
> + stop:
> +	if ((i2c->msg_ptr == i2c->msg->len) || (i2c->state < 0)) {
> +		writel(0, i2c->regs + HSI2C_INT_ENABLE);
> +		exynos5_i2c_clr_pend_irq(i2c);
> +		complete(&i2c->msg_complete);
> +	} else {
> +		exynos5_i2c_clr_pend_irq(i2c);
> +	}
> +
> +	spin_unlock_irqrestore(&i2c->lock, flags);
> +
> +	return IRQ_HANDLED;
> +}
> +

...

> +static int exynos5_i2c_xfer_msg(struct exynos5_i2c *i2c,
> +			      struct i2c_msg *msgs, int stop)
> +{
> +	unsigned long timeout;
> +	int ret;
> +
> +	INIT_COMPLETION(i2c->msg_complete);
> +
> +	spin_lock_irq(&i2c->lock);
> +	i2c->msg = msgs;
> +	i2c->msg_ptr = 0;
> +	i2c->trans_done = 0;
> +
> +	exynos5_i2c_message_start(i2c, stop);
> +
> +	spin_unlock_irq(&i2c->lock);
> +	timeout = wait_for_completion_timeout(&i2c->msg_complete,
> +					      EXYNOS5_I2C_TIMEOUT);
> +	if (timeout == 0)
> +		ret = -ETIMEDOUT;
> +	else
> +		ret = i2c->state;
> +
> +	if (ret < 0) {
> +		exynos5_i2c_reset(i2c);

Do you really need to reset the core after a failed transaction?

> +		if (ret == -ETIMEDOUT) {
> +			dev_warn(i2c->dev, "%s timeout\n",
> +				 (msgs->flags & I2C_M_RD) ? "rx" : "tx");
> +			return ret;
> +		} else if (ret == -EAGAIN) {
> +			return ret;
> +		}
> +	}
> +
> +	/*
> +	 * If this is the last message to be transfered (stop == 1)
> +	 * Then check if the bus can be brought back to idle.
> +	 *
> +	 * Return -EBUSY if the bus still busy.
> +	 */
> +	if (exynos5_i2c_wait_bus_idle(i2c, stop))
> +		return -EBUSY;

Why do you need this after the transaction?

> +
> +	/* Return the state as in interrupt routine */
> +	return ret;
> +}
> +
> +static int exynos5_i2c_xfer(struct i2c_adapter *adap,
> +			struct i2c_msg *msgs, int num)
> +{
> +	struct exynos5_i2c *i2c = (struct exynos5_i2c *)adap->algo_data;
> +	int i = 0, ret = 0, stop = 0;
> +
> +	if (i2c->suspended) {
> +		dev_err(i2c->dev, "HS-I2C is not initialzed.\n");
> +		return -EIO;
> +	}
> +
> +	clk_prepare_enable(i2c->clk);
> +
> +	for (i = 0; i < num; i++) {
> +		stop = (i == num - 1);
> +
> +		if (msgs->len == 0) {

Did you need that? It shouldn't happen since you are not advertising
SMBUS_QUICK.

> +			msgs++;
> +			continue;
> +		}
> +
> +		ret = exynos5_i2c_xfer_msg(i2c, msgs, stop);
> +		if (!stop)
> +			msgs++;

Probably better put in the for-body (i.e. i++, msgs++).

> +
> +		if (ret < 0)
> +			goto out;
> +	}
> +
> +	if (i == num) {
> +		ret = num;
> +	} else {
> +		/* Only one message, cannot access the device */
> +		if (i == 1)
> +			ret = -EREMOTEIO;
> +		else
> +			ret = i;
> +
> +		dev_warn(i2c->dev, "xfer message failed\n");
> +	}
> +
> + out:
> +	clk_disable_unprepare(i2c->clk);
> +	return ret;
> +}
> +
> +static u32 exynos5_i2c_func(struct i2c_adapter *adap)
> +{
> +	return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);
> +}
> +
> +static const struct i2c_algorithm exynos5_i2c_algorithm = {
> +	.master_xfer		= exynos5_i2c_xfer,
> +	.functionality		= exynos5_i2c_func,
> +};
> +
> +static int exynos5_i2c_probe(struct platform_device *pdev)
> +{
> +	struct device_node *np = pdev->dev.of_node;
> +	struct exynos5_i2c *i2c;
> +	struct resource *mem;
> +	unsigned int op_clock;
> +	int ret;
> +
> +	if (!np) {
> +		dev_err(&pdev->dev, "no device node\n");
> +		return -ENOENT;
> +	}

How should this happen?

> +
> +	i2c = devm_kzalloc(&pdev->dev, sizeof(struct exynos5_i2c), GFP_KERNEL);
> +	if (!i2c) {
> +		dev_err(&pdev->dev, "no memory for state\n");
> +		return -ENOMEM;
> +	}
> +

...

> +	i2c->adap.nr = -1;
> +	ret = i2c_add_numbered_adapter(&i2c->adap);

Just use i2c_add_adapter and skip setting nr to -1.

...

> +static const struct dev_pm_ops exynos5_i2c_dev_pm_ops = {
> +	.suspend_noirq = exynos5_i2c_suspend_noirq,
> +	.resume_noirq	= exynos5_i2c_resume_noirq,
> +};
> +
> +#define EXYNOS5_DEV_PM_OPS (&exynos5_i2c_dev_pm_ops)
> +#else
> +#define EXYNOS5_DEV_PM_OPS NULL
> +#endif

Isn't there a macro for this? SIMPLE_DEV_PM_OPS*? Not sure, I always mix
them up...

Regards,

   Wolfram


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

WARNING: multiple messages have this Message-ID (diff)
From: Wolfram Sang <wsa-z923LK4zBo2bacvFa/9K2g@public.gmane.org>
To: Naveen Krishna Chatradhi
	<ch.naveen-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
Cc: linux-i2c-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	linux-samsung-soc-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	w.sang-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org,
	t.figa-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org,
	ben-linux-elnMNo+KYs3YtjvyW6yDsg@public.gmane.org,
	grant.likely-s3s/WqlpOiPyB63q8FvJNQ@public.gmane.org,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ@public.gmane.org,
	sjg-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org,
	naveenkrishna.ch-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org,
	broonie-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E@public.gmane.org
Subject: Re: [PATCH] i2c: exynos5: add High Speed I2C controller driver
Date: Sun, 8 Sep 2013 19:03:56 +0200	[thread overview]
Message-ID: <20130908170355.GA3154@katana> (raw)
In-Reply-To: <1377077077-20896-1-git-send-email-ch.naveen-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>

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


On Wed, Aug 21, 2013 at 02:54:37PM +0530, Naveen Krishna Ch wrote:
> Adds support for High Speed I2C driver found in Exynos5 and
> later SoCs from Samsung.
> 
> Highspeed mode is a minor change in the i2c protocol.
> Starts with
> 1. start condition,
> 2. 8-bit master ID code (00001xxx)
> 3. followed by a NACK bit
> Once the above conditions are met, the bus is now operates in highspeed mode.
> The rest of the I2C protocol applies the same.

The description is correct, but it is not a change in the protocol. This
is fully specified in the I2C specs.

> Driver only supports Device Tree method.
> 
> Changes since v1:
> 1. Added FIFO functionality
> 2. Added High speed mode functionality
> 3. Remove SMBUS_QUICK
> 4. Remove the debugfs functionality
> 5. Use devm_* functions where ever possible
> 6. Driver is free from GPIO configs
> 7. Use OF data string "clock-frequency" to get the bus operating frequencies
> 8. Split the clock divisor calculation function
> 9. Add resets for the failed transacton cases
> 10. Removed retries as core does retries if -EAGAIN is returned
> 11. Removed mode from device tree info (use speed to distinguish
>     the mode of operation)
> 12. Use wait_for_completion_timeout as the interruptible case is not tested well
> 13. few other bug fixes and cosmetic changes
> 14. Removed the untested runtime_pm code
> 15. Removed the retries as core does that
> 16. Use adap.nr instead of alias
> 17. Added spinlocks around the irq code
> 18. Use i2c_add_numbered_adapter() instead of using aliases

Changes since v1 are irrelevant for the patch description.

> 
> Signed-off-by: Taekgyun Ko <taeggyun.ko-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> Signed-off-by: Naveen Krishna Chatradhi <ch.naveen-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> Reviewed-by: Simon Glass <sjg-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org>
> Tested-by: Andrew Bresticker <abrestic-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org>
> Signed-off-by: Yuvaraj Kumar C D <yuvaraj.cd-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> Signed-off-by: Andrew Bresticker <abrestic-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org>
> 
> ---
> Wolfram and Thomas Figa thanks for reviewing the code.
> 
> Changes since v10:
> 1. Remove the incomplete runtime_pm code
> 2. Correct the error checks as suggested by Thomas
> 3. Use i2c_add_numbered_adapter() as suggested
> 4. Modified the irq routine to handle the specific interrupts
> 5. Added spinlocks around the irq code
> 6. Remove the "mode" of operation field from device tree node and use the
>    clock-frequency to decide the mode.
> 
>  .../devicetree/bindings/i2c/i2c-exynos5.txt        |   44 ++
>  drivers/i2c/busses/Kconfig                         |    7 +
>  drivers/i2c/busses/Makefile                        |    1 +
>  drivers/i2c/busses/i2c-exynos5.c                   |  799 ++++++++++++++++++++
>  4 files changed, 851 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/i2c/i2c-exynos5.txt
>  create mode 100644 drivers/i2c/busses/i2c-exynos5.c
> 
> diff --git a/Documentation/devicetree/bindings/i2c/i2c-exynos5.txt b/Documentation/devicetree/bindings/i2c/i2c-exynos5.txt
> new file mode 100644
> index 0000000..805e018
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/i2c/i2c-exynos5.txt
> @@ -0,0 +1,44 @@
> +* Samsung's High Speed I2C controller
> +
> +The Samsung's High Speed I2C controller is used to interface with I2C devices
> +at various speeds ranging from 100khz to 3.4Mhz.
> +
> +Required properties:
> +  - compatible: value should be.
> +      -> "samsung,exynos5-hsi2c", for i2c compatible with exynos5 hsi2c.
> +  - reg: physical base address of the controller and length of memory mapped
> +    region.
> +  - interrupts: interrupt number to the cpu.
> +  - #address-cells: always 1 (for i2c addresses)
> +  - #size-cells: always 0
> +
> +  - Pinctrl:
> +    - pinctrl-0: Pin control group to be used for this controller.
> +    - pinctrl-names: Should contain only one value - "default".
> +
> +Optional properties:
> +  - clock-frequency: Desired operating frequency in Hz of the bus.
> +    -> If not specified, the default value is 100khz in fast-speed mode and
> +       1Mhz in high-speed mode.

Description doesn't match the current code.

> +    -> If specified, The bus operates in high-speed mode only if the
> +       clock-frequency is >= 1Mhz.

s/The/the/

...

> +/*
> + * exynos5_i2c_init: configures the controller for I2C functionality
> + * Programs I2C controller for Master mode operation
> + */
> +static void exynos5_i2c_init(struct exynos5_i2c *i2c)
> +{
> +	u32 i2c_conf = readl(i2c->regs + HSI2C_CONF);
> +	u32 i2c_timeout = readl(i2c->regs + HSI2C_TIMEOUT);
> +
> +	/* Disable timeout */
> +	i2c_timeout &= ~HSI2C_TIMEOUT_EN;
> +	writel(i2c_timeout, i2c->regs + HSI2C_TIMEOUT);

Just curious: Can't you use HSI2C_TIMEOUT and wait_for_completion
instead of wait_for_completion_timeout? If so, it might save you a
little bit of overhead.

> +
> +	writel((HSI2C_FUNC_MODE_I2C | HSI2C_MASTER),
> +					i2c->regs + HSI2C_CTL);
> +	writel(HSI2C_TRAILING_COUNT, i2c->regs + HSI2C_TRAILIG_CTL);
> +
> +	if (i2c->speed_mode == HSI2C_HIGH_SPD) {
> +		writel(HSI2C_MASTER_ID(MASTER_ID(i2c->adap.nr)),
> +					i2c->regs + HSI2C_ADDR);
> +		i2c_conf |= HSI2C_HS_MODE;
> +	}
> +
> +	writel(i2c_conf | HSI2C_AUTO_MODE, i2c->regs + HSI2C_CONF);
> +}
> +
> +
> +	if ((i2c->msg->flags & I2C_M_RD) && (int_status &
> +			(HSI2C_INT_TRAILING | HSI2C_INT_RX_ALMOSTFULL))) {
> +		fifo_status = readl(i2c->regs + HSI2C_FIFO_STATUS);
> +		fifo_level = HSI2C_RX_FIFO_LVL(fifo_status);
> +		len = min(fifo_level, i2c->msg->len - i2c->msg_ptr);
> +
> +		while (len > 0) {
> +			byte = (unsigned char)
> +				readl(i2c->regs + HSI2C_RX_DATA);
> +			i2c->msg->buf[i2c->msg_ptr++] = byte;
> +			len--;
> +		}

With all this copying going on, this should be threaded irq probably.

> +		i2c->state = 0;
> +	} else if (int_status & HSI2C_INT_TX_ALMOSTEMPTY) {
> +		fifo_status = readl(i2c->regs + HSI2C_FIFO_STATUS);
> +		fifo_level = HSI2C_TX_FIFO_LVL(fifo_status);
> +
> +		len = HSI2C_FIFO_MAX - fifo_level;
> +		if (len > (i2c->msg->len - i2c->msg_ptr))
> +			len = i2c->msg->len - i2c->msg_ptr;
> +
> +		while (len > 0) {
> +			byte = i2c->msg->buf[i2c->msg_ptr++];
> +			writel(byte, i2c->regs + HSI2C_TX_DATA);
> +			len--;
> +		}
> +		i2c->state = 0;
> +	}
> +
> + stop:
> +	if ((i2c->msg_ptr == i2c->msg->len) || (i2c->state < 0)) {
> +		writel(0, i2c->regs + HSI2C_INT_ENABLE);
> +		exynos5_i2c_clr_pend_irq(i2c);
> +		complete(&i2c->msg_complete);
> +	} else {
> +		exynos5_i2c_clr_pend_irq(i2c);
> +	}
> +
> +	spin_unlock_irqrestore(&i2c->lock, flags);
> +
> +	return IRQ_HANDLED;
> +}
> +

...

> +static int exynos5_i2c_xfer_msg(struct exynos5_i2c *i2c,
> +			      struct i2c_msg *msgs, int stop)
> +{
> +	unsigned long timeout;
> +	int ret;
> +
> +	INIT_COMPLETION(i2c->msg_complete);
> +
> +	spin_lock_irq(&i2c->lock);
> +	i2c->msg = msgs;
> +	i2c->msg_ptr = 0;
> +	i2c->trans_done = 0;
> +
> +	exynos5_i2c_message_start(i2c, stop);
> +
> +	spin_unlock_irq(&i2c->lock);
> +	timeout = wait_for_completion_timeout(&i2c->msg_complete,
> +					      EXYNOS5_I2C_TIMEOUT);
> +	if (timeout == 0)
> +		ret = -ETIMEDOUT;
> +	else
> +		ret = i2c->state;
> +
> +	if (ret < 0) {
> +		exynos5_i2c_reset(i2c);

Do you really need to reset the core after a failed transaction?

> +		if (ret == -ETIMEDOUT) {
> +			dev_warn(i2c->dev, "%s timeout\n",
> +				 (msgs->flags & I2C_M_RD) ? "rx" : "tx");
> +			return ret;
> +		} else if (ret == -EAGAIN) {
> +			return ret;
> +		}
> +	}
> +
> +	/*
> +	 * If this is the last message to be transfered (stop == 1)
> +	 * Then check if the bus can be brought back to idle.
> +	 *
> +	 * Return -EBUSY if the bus still busy.
> +	 */
> +	if (exynos5_i2c_wait_bus_idle(i2c, stop))
> +		return -EBUSY;

Why do you need this after the transaction?

> +
> +	/* Return the state as in interrupt routine */
> +	return ret;
> +}
> +
> +static int exynos5_i2c_xfer(struct i2c_adapter *adap,
> +			struct i2c_msg *msgs, int num)
> +{
> +	struct exynos5_i2c *i2c = (struct exynos5_i2c *)adap->algo_data;
> +	int i = 0, ret = 0, stop = 0;
> +
> +	if (i2c->suspended) {
> +		dev_err(i2c->dev, "HS-I2C is not initialzed.\n");
> +		return -EIO;
> +	}
> +
> +	clk_prepare_enable(i2c->clk);
> +
> +	for (i = 0; i < num; i++) {
> +		stop = (i == num - 1);
> +
> +		if (msgs->len == 0) {

Did you need that? It shouldn't happen since you are not advertising
SMBUS_QUICK.

> +			msgs++;
> +			continue;
> +		}
> +
> +		ret = exynos5_i2c_xfer_msg(i2c, msgs, stop);
> +		if (!stop)
> +			msgs++;

Probably better put in the for-body (i.e. i++, msgs++).

> +
> +		if (ret < 0)
> +			goto out;
> +	}
> +
> +	if (i == num) {
> +		ret = num;
> +	} else {
> +		/* Only one message, cannot access the device */
> +		if (i == 1)
> +			ret = -EREMOTEIO;
> +		else
> +			ret = i;
> +
> +		dev_warn(i2c->dev, "xfer message failed\n");
> +	}
> +
> + out:
> +	clk_disable_unprepare(i2c->clk);
> +	return ret;
> +}
> +
> +static u32 exynos5_i2c_func(struct i2c_adapter *adap)
> +{
> +	return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);
> +}
> +
> +static const struct i2c_algorithm exynos5_i2c_algorithm = {
> +	.master_xfer		= exynos5_i2c_xfer,
> +	.functionality		= exynos5_i2c_func,
> +};
> +
> +static int exynos5_i2c_probe(struct platform_device *pdev)
> +{
> +	struct device_node *np = pdev->dev.of_node;
> +	struct exynos5_i2c *i2c;
> +	struct resource *mem;
> +	unsigned int op_clock;
> +	int ret;
> +
> +	if (!np) {
> +		dev_err(&pdev->dev, "no device node\n");
> +		return -ENOENT;
> +	}

How should this happen?

> +
> +	i2c = devm_kzalloc(&pdev->dev, sizeof(struct exynos5_i2c), GFP_KERNEL);
> +	if (!i2c) {
> +		dev_err(&pdev->dev, "no memory for state\n");
> +		return -ENOMEM;
> +	}
> +

...

> +	i2c->adap.nr = -1;
> +	ret = i2c_add_numbered_adapter(&i2c->adap);

Just use i2c_add_adapter and skip setting nr to -1.

...

> +static const struct dev_pm_ops exynos5_i2c_dev_pm_ops = {
> +	.suspend_noirq = exynos5_i2c_suspend_noirq,
> +	.resume_noirq	= exynos5_i2c_resume_noirq,
> +};
> +
> +#define EXYNOS5_DEV_PM_OPS (&exynos5_i2c_dev_pm_ops)
> +#else
> +#define EXYNOS5_DEV_PM_OPS NULL
> +#endif

Isn't there a macro for this? SIMPLE_DEV_PM_OPS*? Not sure, I always mix
them up...

Regards,

   Wolfram


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

  reply	other threads:[~2013-09-08 17:04 UTC|newest]

Thread overview: 113+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-11-27 13:00 [PATCH 0/3] i2c: Add High speed I2C controller driver for Exynos5 Naveen Krishna Chatradhi
2012-11-27 13:00 ` Naveen Krishna Chatradhi
2012-11-27 13:00 ` [PATCH 1/3] i2c: exynos5: add High Speed I2C controller driver Naveen Krishna Chatradhi
2012-11-27 13:00   ` Naveen Krishna Chatradhi
2012-11-27 13:23   ` Felipe Balbi
2012-11-27 13:23     ` Felipe Balbi
2012-11-27 13:23     ` Felipe Balbi
2012-11-27 13:34   ` Thomas Abraham
2012-11-27 13:34     ` Thomas Abraham
2012-11-27 13:34     ` Thomas Abraham
2012-11-28  4:23     ` Naveen Krishna Ch
2012-11-28  4:23       ` Naveen Krishna Ch
2012-11-28  4:23       ` Naveen Krishna Ch
2012-12-25 11:25   ` [PATCH 1/2] " Naveen Krishna Chatradhi
2012-12-25 11:25     ` Naveen Krishna Chatradhi
2012-12-25 11:25     ` Naveen Krishna Chatradhi
2012-12-25 11:25     ` [PATCH 2/2] i2c-exynos5: add debugfs support for registers Naveen Krishna Chatradhi
2012-12-25 11:25       ` Naveen Krishna Chatradhi
2012-12-25 11:25       ` Naveen Krishna Chatradhi
2012-12-27 22:57       ` Felipe Balbi
2012-12-27 22:57         ` Felipe Balbi
2012-12-27 22:57         ` Felipe Balbi
2012-12-27 22:59       ` Felipe Balbi
2012-12-27 22:59         ` Felipe Balbi
2012-12-27 22:59         ` Felipe Balbi
2012-12-27 22:57     ` [PATCH 1/2] i2c: exynos5: add High Speed I2C controller driver Felipe Balbi
2012-12-27 22:57       ` Felipe Balbi
2012-12-27 22:57       ` Felipe Balbi
2012-12-28  6:42       ` Naveen Krishna Ch
2012-12-28  6:42         ` Naveen Krishna Ch
2012-12-28 11:27   ` [PATCH v3] " Naveen Krishna Chatradhi
2012-12-28 11:27     ` Naveen Krishna Chatradhi
2012-12-28 11:27     ` Naveen Krishna Chatradhi
2012-12-28 16:36     ` Naveen Krishna Ch
2012-12-28 16:36       ` Naveen Krishna Ch
2012-12-28 16:36       ` Naveen Krishna Ch
2013-01-15  6:23       ` Naveen Krishna Ch
2013-01-15  6:23         ` Naveen Krishna Ch
2013-01-23  5:05     ` Naveen Krishna Ch
2013-01-23  5:05       ` Naveen Krishna Ch
2013-01-23  5:05       ` Naveen Krishna Ch
2013-02-01 15:54   ` [PATCH v4] " Naveen Krishna Chatradhi
2013-02-01 15:54     ` Naveen Krishna Chatradhi
2013-02-01 19:29     ` Wolfram Sang
2013-02-01 19:29       ` Wolfram Sang
2013-02-08 13:16     ` Grant Likely
2013-03-12  4:32   ` [PATCH] " Naveen Krishna Chatradhi
     [not found]     ` <1363062732-27869-1-git-send-email-ch.naveen-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
2013-03-12 12:53       ` Simon Glass
2013-03-12 13:13     ` Simon Glass
2013-03-12 13:13       ` Simon Glass
2013-03-20 16:26       ` Naveen Krishna Ch
2013-03-20 16:26         ` Naveen Krishna Ch
2013-03-20 16:24     ` [RFC: PATCH v5] " Naveen Krishna Chatradhi
2013-03-20 16:24       ` Naveen Krishna Chatradhi
2013-03-25 11:52       ` Yuvaraj CD
2013-03-26  9:23         ` Wolfram Sang
2013-03-28 22:01   ` [PATCH v6] " Naveen Krishna Chatradhi
2013-03-28 23:40   ` Naveen Krishna Chatradhi
2013-03-28 23:40     ` Naveen Krishna Chatradhi
2013-04-05  4:52   ` [PATCH v7] " Naveen Krishna Chatradhi
2013-04-13  4:40     ` Naveen Krishna Ch
2013-04-13  4:40       ` Naveen Krishna Ch
2013-04-16 10:29     ` Wolfram Sang
     [not found]       ` <CAHfPSqCe_VJMeH3oCDc0CfcmpawMj0hN7_b3ngHDFtDUsPJLsA@mail.gmail.com>
2013-05-01 23:19         ` Fwd: " Naveen Krishna Ch
2013-05-01 23:19           ` Naveen Krishna Ch
2013-05-02 11:27           ` Wolfram Sang
2013-05-02 11:27             ` Wolfram Sang
2013-05-02 11:48             ` Naveen Krishna Ch
2013-05-02 11:48               ` Naveen Krishna Ch
2013-05-07  2:50   ` [PATCH v8] " Naveen Krishna Chatradhi
2013-05-07  2:50     ` Naveen Krishna Chatradhi
2013-05-07 12:06     ` Sachin Kamat
2013-05-17 10:10   ` [PATCH v9] " Naveen Krishna Chatradhi
2013-05-17 10:10     ` Naveen Krishna Chatradhi
2013-05-23  6:29     ` Naveen Krishna Ch
2013-05-23  6:29       ` Naveen Krishna Ch
     [not found]     ` <1368785452-15140-1-git-send-email-ch.naveen-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
2013-06-10  8:07       ` Naveen Krishna Ch
2013-06-10  8:10     ` Naveen Krishna Ch
2013-06-10  8:10       ` Naveen Krishna Ch
2013-06-10 14:38     ` Wolfram Sang
2013-06-19 10:48   ` [PATCH v10] " Naveen Krishna Chatradhi
2013-06-19 10:48     ` Naveen Krishna Chatradhi
2013-06-19 10:48     ` Naveen Krishna Chatradhi
2013-07-01  6:17     ` Wolfram Sang
2013-07-01  6:17       ` Wolfram Sang
2013-07-01  6:17       ` Wolfram Sang
2013-07-01 10:25     ` Tomasz Figa
2013-07-01 10:25       ` Tomasz Figa
2013-07-01 10:25       ` Tomasz Figa
2013-08-15 13:12       ` Wolfram Sang
2013-08-15 13:12         ` Wolfram Sang
2013-08-16  4:58         ` Naveen Krishna Ch
2013-08-16  4:58           ` Naveen Krishna Ch
2013-08-16  4:58           ` Naveen Krishna Ch
2013-08-16  7:05           ` Wolfram Sang
2013-08-16  7:05             ` Wolfram Sang
2013-08-16  7:05             ` Wolfram Sang
2013-08-21  9:24   ` [PATCH] " Naveen Krishna Chatradhi
2013-08-21  9:24     ` Naveen Krishna Chatradhi
2013-09-08 17:03     ` Wolfram Sang [this message]
2013-09-08 17:03       ` Wolfram Sang
2013-10-11 11:43       ` Naveen Krishna Ch
2013-10-11 11:43         ` Naveen Krishna Ch
2013-10-16  5:30   ` [PATCH v12] " Naveen Krishna Chatradhi
2013-10-25 11:47     ` Naveen Krishna Ch
2013-10-25 11:47       ` Naveen Krishna Ch
2013-11-01 11:35     ` Wolfram Sang
2012-11-27 13:00 ` [PATCH 2/3] ARM: exynos5: Add gate clocks for HS-I2C Naveen Krishna Chatradhi
2012-11-27 13:00   ` Naveen Krishna Chatradhi
2012-11-27 13:00   ` Naveen Krishna Chatradhi
2012-11-27 13:00 ` [PATCH 3/3] arm: exynos5: Add HS-I2C device tree platform information Naveen Krishna Chatradhi
2012-11-27 13:00   ` Naveen Krishna Chatradhi
2012-11-27 13:00   ` Naveen Krishna Chatradhi

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=20130908170355.GA3154@katana \
    --to=wsa@the-dreams.de \
    --cc=ben-linux@fluff.org \
    --cc=broonie@opensource.wolfsonmicro.com \
    --cc=ch.naveen@samsung.com \
    --cc=devicetree-discuss@lists.ozlabs.org \
    --cc=grant.likely@secretlab.ca \
    --cc=linux-i2c@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-samsung-soc@vger.kernel.org \
    --cc=naveenkrishna.ch@gmail.com \
    --cc=sjg@chromium.org \
    --cc=t.figa@samsung.com \
    --cc=w.sang@pengutronix.de \
    /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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.