Linux I2C development
 help / color / mirror / Atom feed
* Re: [PATCH v2] i2c: designware: add reset interface
From: zhangfei @ 2016-12-16  3:01 UTC (permalink / raw)
  To: Ramiro Oliveira, Andy Shevchenko, Wolfram Sang,
	mika.westerberg@linux.intel.com, jarkko.nikula@linux.intel.com,
	Philipp Zabel
  Cc: linux-arm-kernel@lists.infradead.org, linux-i2c@vger.kernel.org
In-Reply-To: <fd0afd5f-6ee4-a06f-2d03-444f71662c1b@linaro.org>

Hi, Philipp


On 2016年12月16日 10:45, zhangfei wrote:
>
>
> On 2016年12月15日 23:30, Ramiro Oliveira wrote:
>> Hi Andy and Zhangfei
>>
>> On 12/15/2016 12:33 PM, Andy Shevchenko wrote:
>>> On Thu, 2016-12-15 at 16:59 +0800, Zhangfei Gao wrote:
>>>> Some platforms like hi3660 need do reset first to allow accessing
>>>> registers
>>> Patch itself looks good, but would be nice to have it tested.
>>>
>>> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
>>>
>> I tested the patch and it's working for the ARC architecture.
>>
>>>> Signed-off-by: Zhangfei Gao <zhangfei.gao@linaro.org>
>>>> ---
>>>>   drivers/i2c/busses/i2c-designware-core.h    |  1 +
>>>>   drivers/i2c/busses/i2c-designware-platdrv.c | 28
>>>> ++++++++++++++++++++++++----
>>>>   2 files changed, 25 insertions(+), 4 deletions(-)
>>>>
>>>> diff --git a/drivers/i2c/busses/i2c-designware-core.h
>>>> b/drivers/i2c/busses/i2c-designware-core.h
>>>> index 0d44d2a..94b14fa 100644
>>>> --- a/drivers/i2c/busses/i2c-designware-core.h
>>>> +++ b/drivers/i2c/busses/i2c-designware-core.h
>>>> @@ -80,6 +80,7 @@ struct dw_i2c_dev {
>>>>       void __iomem        *base;
>>>>       struct completion    cmd_complete;
>>>>       struct clk        *clk;
>>>> +    struct reset_control    *rst;
>>>>       u32            (*get_clk_rate_khz) (struct
>>>> dw_i2c_dev *dev);
>>>>       struct dw_pci_controller *controller;
>>>>       int            cmd_err;
>>>> diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c
>>>> b/drivers/i2c/busses/i2c-designware-platdrv.c
>>>> index 0b42a12..e9016ae 100644
>>>> --- a/drivers/i2c/busses/i2c-designware-platdrv.c
>>>> +++ b/drivers/i2c/busses/i2c-designware-platdrv.c
>>>> @@ -38,6 +38,7 @@
>>>>   #include <linux/pm_runtime.h>
>>>>   #include <linux/property.h>
>>>>   #include <linux/io.h>
>>>> +#include <linux/reset.h>
>>>>   #include <linux/slab.h>
>>>>   #include <linux/acpi.h>
>>>>   #include <linux/platform_data/i2c-designware.h>
>>>> @@ -176,6 +177,14 @@ static int dw_i2c_plat_probe(struct
>>>> platform_device *pdev)
>>>>       dev->irq = irq;
>>>>       platform_set_drvdata(pdev, dev);
>>>>   +    dev->rst = devm_reset_control_get_optional(&pdev->dev, NULL);
>> devm_reset_control_get_optional() is deprecated as explained in 
>> linux/reset.h,
>> you should use devm_reset_control_get_optional_exclusive() or
>> devm_reset_control_get_optional_shared() instead, as applicable.
>>
>> I submitted a similar patch earlier today and I made the same mistake.
>
> Thanks Ramiro for the info
> Will use devm_reset_control_get_optional_exclusive instead.
> But should the interface be as simple as possible?
>
> Thanks
Sorry, a bit confused.
Is that mean we should not use devm_reset_control_get_optional()
While driver should decide whether use 
devm_reset_control_get_optional_exclusive() or
devm_reset_control_get_optional_shared()
What if different platform has different requirement?

Looks the difference between _exclusive and _shared is refcount,
How about handle this inside, and not decided by interface?

Thanks

^ permalink raw reply

* Re: [PATCH v2] i2c: designware: add reset interface
From: zhangfei @ 2016-12-16  2:45 UTC (permalink / raw)
  To: Ramiro Oliveira, Andy Shevchenko, Wolfram Sang,
	mika.westerberg@linux.intel.com, jarkko.nikula@linux.intel.com
  Cc: linux-arm-kernel@lists.infradead.org, linux-i2c@vger.kernel.org
In-Reply-To: <fda7e3ef-5bc1-9837-b421-4293baa3de34@synopsys.com>



On 2016年12月15日 23:30, Ramiro Oliveira wrote:
> Hi Andy and Zhangfei
>
> On 12/15/2016 12:33 PM, Andy Shevchenko wrote:
>> On Thu, 2016-12-15 at 16:59 +0800, Zhangfei Gao wrote:
>>> Some platforms like hi3660 need do reset first to allow accessing
>>> registers
>> Patch itself looks good, but would be nice to have it tested.
>>
>> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
>>
> I tested the patch and it's working for the ARC architecture.
>
>>> Signed-off-by: Zhangfei Gao <zhangfei.gao@linaro.org>
>>> ---
>>>   drivers/i2c/busses/i2c-designware-core.h    |  1 +
>>>   drivers/i2c/busses/i2c-designware-platdrv.c | 28
>>> ++++++++++++++++++++++++----
>>>   2 files changed, 25 insertions(+), 4 deletions(-)
>>>
>>> diff --git a/drivers/i2c/busses/i2c-designware-core.h
>>> b/drivers/i2c/busses/i2c-designware-core.h
>>> index 0d44d2a..94b14fa 100644
>>> --- a/drivers/i2c/busses/i2c-designware-core.h
>>> +++ b/drivers/i2c/busses/i2c-designware-core.h
>>> @@ -80,6 +80,7 @@ struct dw_i2c_dev {
>>>   	void __iomem		*base;
>>>   	struct completion	cmd_complete;
>>>   	struct clk		*clk;
>>> +	struct reset_control	*rst;
>>>   	u32			(*get_clk_rate_khz) (struct
>>> dw_i2c_dev *dev);
>>>   	struct dw_pci_controller *controller;
>>>   	int			cmd_err;
>>> diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c
>>> b/drivers/i2c/busses/i2c-designware-platdrv.c
>>> index 0b42a12..e9016ae 100644
>>> --- a/drivers/i2c/busses/i2c-designware-platdrv.c
>>> +++ b/drivers/i2c/busses/i2c-designware-platdrv.c
>>> @@ -38,6 +38,7 @@
>>>   #include <linux/pm_runtime.h>
>>>   #include <linux/property.h>
>>>   #include <linux/io.h>
>>> +#include <linux/reset.h>
>>>   #include <linux/slab.h>
>>>   #include <linux/acpi.h>
>>>   #include <linux/platform_data/i2c-designware.h>
>>> @@ -176,6 +177,14 @@ static int dw_i2c_plat_probe(struct
>>> platform_device *pdev)
>>>   	dev->irq = irq;
>>>   	platform_set_drvdata(pdev, dev);
>>>   
>>> +	dev->rst = devm_reset_control_get_optional(&pdev->dev, NULL);
> devm_reset_control_get_optional() is deprecated as explained in linux/reset.h,
> you should use devm_reset_control_get_optional_exclusive() or
> devm_reset_control_get_optional_shared() instead, as applicable.
>
> I submitted a similar patch earlier today and I made the same mistake.

Thanks Ramiro for the info
Will use devm_reset_control_get_optional_exclusive instead.
But should the interface be as simple as possible?

Thanks

^ permalink raw reply

* [PULL REQUEST] i2c for 4.10
From: Wolfram Sang @ 2016-12-15 20:35 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: linux-i2c, linux-kernel

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

Linus,

here is the first pull request from I2C for 4.10, including:

* the first series of making i2c_device_id optional instead of mandatory
  (in favor of alternatives like of_device_id). This involves adding a
  new probe callback (probe_new) which removes some peculiarities I2C had
  for a long time now. The new probe is matching the other subsystems
  now and the old one will be removed once all users are converted. It
  is expected to take a while but there is ongoing interest in that.
* SMBus Host Notify introduced 4.9 got refactored. They are now using
  interrupts instead of the alert callback which solves multiple issues.
* new drivers for iMX LowPower I2C, Mellanox CPLD and its I2C mux
* significant refactoring for bcm2835 driver
* usual set of driver updates and improvements

Thanks,

   Wolfram


The following changes since commit bc33b0ca11e3df467777a4fa7639ba488c9d4911:

  Linux 4.9-rc4 (2016-11-05 16:23:36 -0700)

are available in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux.git i2c/for-4.10

for you to fetch changes up to 6eb89ef029fe22aee518a9dc75b9ee5d6ef9b3fe:

  i2c: fsl-lpi2c: read lpi2c fifo size in probe() (2016-12-11 23:06:39 +0100)

----------------------------------------------------------------
Alexander Stein (2):
      i2c: designware: Consolidate default functionality bits
      i2c: designware-pcidrv: Add 10bit address feature to medfield/merrifield

Benjamin Tissoires (6):
      i2c: i801: store and restore the SLVCMD register at load and unload
      i2c: i801: minor formatting issues
      i2c: i801: use BIT() macro for bits definition
      i2c: i801: use the BIT() macro for FEATURES_* also
      i2c: i801: remove SMBNTFDDAT reads as they always seem to return 0
      i2c: use an IRQ to report Host Notify events, not alert

Gao Pan (3):
      dt-bindings: i2c: imx-lpi2c: add devicetree bindings
      i2c: imx-lpi2c: add low power i2c bus driver
      i2c: fsl-lpi2c: read lpi2c fifo size in probe()

Jan Glauber (2):
      i2c: octeon: thunderx: TWSI software reset in recovery
      i2c: octeon: thunderx: Remove double-check after interrupt

Jan Kotas (1):
      i2c: cadence: Allow Cadence I2C to be selected for Cadence Xtensa CPUs

Jarkko Nikula (1):
      i2c: designware: Allow reduce bus speed by "clock-frequency" property

Julia Lawall (1):
      i2c: constify i2c_adapter_quirks structures

Lee Jones (7):
      i2c: Add pointer dereference protection to i2c_match_id()
      i2c: Add the ability to match device to compatible string without an of_node
      i2c: Match using traditional OF methods, then by vendor-less compatible strings
      i2c: Make I2C ID tables non-mandatory for DT'ed devices
      i2c: Export i2c_match_id() for direct use by device drivers
      i2c: Provide a temporary .probe_new() call-back type
      mfd: 88pm860x: Move over to new I2C device .probe() call

Masahiro Yamada (2):
      i2c: uniphier: rename jump label to follow coding style guideline
      i2c: uniphier-f: rename jump label to follow coding style guideline

Naveen Kaje (2):
      i2c: qup: add ACPI support
      i2c: qup: support SMBus block read

Noralf Trønnes (7):
      i2c: bcm2835: Fix hang for writing messages larger than 16 bytes
      i2c: bcm2835: Protect against unexpected TXW/RXR interrupts
      i2c: bcm2835: Use dev_dbg logging on transfer errors
      i2c: bcm2835: Can't support I2C_M_IGNORE_NAK
      i2c: bcm2835: Add support for Repeated Start Condition
      i2c: bcm2835: Support i2c-dev ioctl I2C_TIMEOUT
      i2c: bcm2835: Add support for dynamic clock

Paul Gortmaker (1):
      i2c: i2c-pxa-pci; make explicitly non-modular

Peter Rosin (1):
      i2c: i2c-mux-gpio: update mux with gpiod_set_array_value_cansleep

Romain Perier (3):
      dt-bindings: i2c: pxa: Update the documentation for the Armada 3700
      i2c: pxa: Add definition of fast and high speed modes via the regs layout
      i2c: pxa: Add support for the I2C units found in Armada 3700

Simon Horman (2):
      i2c: rcar: Add per-Generation fallback bindings
      i2c: sh_mobile: Add per-Generation fallback bindings

Tanmay Jagdale (1):
      i2c: xlp9xx: ACPI support for I2C clients

Tin Huynh (1):
      i2c: designware: Implement support for SMBus block read and write

Vadim Pasternak (2):
      i2c: mux: mellanox: add driver
      i2c: mlxcpld: add master driver for mellanox systems

tnhuynh@apm.com (1):
      i2c: mux: pca954x: Add ACPI support for pca954x

 .../devicetree/bindings/i2c/i2c-imx-lpi2c.txt      |  20 +
 Documentation/devicetree/bindings/i2c/i2c-pxa.txt  |   1 +
 Documentation/devicetree/bindings/i2c/i2c-rcar.txt |  32 +-
 .../devicetree/bindings/i2c/i2c-sh_mobile.txt      |  17 +-
 Documentation/i2c/busses/i2c-mlxcpld               |  47 ++
 Documentation/i2c/smbus-protocol                   |  12 +-
 MAINTAINERS                                        |   9 +
 drivers/i2c/Kconfig                                |   1 +
 drivers/i2c/busses/Kconfig                         |  25 +-
 drivers/i2c/busses/Makefile                        |   2 +
 drivers/i2c/busses/i2c-axxia.c                     |   2 +-
 drivers/i2c/busses/i2c-bcm-iproc.c                 |   2 +-
 drivers/i2c/busses/i2c-bcm2835.c                   | 218 ++++---
 drivers/i2c/busses/i2c-designware-core.c           |  46 +-
 drivers/i2c/busses/i2c-designware-core.h           |   8 +
 drivers/i2c/busses/i2c-designware-pcidrv.c         |  10 +-
 drivers/i2c/busses/i2c-designware-platdrv.c        |  23 +-
 drivers/i2c/busses/i2c-dln2.c                      |   2 +-
 drivers/i2c/busses/i2c-i801.c                      | 123 ++--
 drivers/i2c/busses/i2c-imx-lpi2c.c                 | 652 +++++++++++++++++++++
 drivers/i2c/busses/i2c-mlxcpld.c                   | 504 ++++++++++++++++
 drivers/i2c/busses/i2c-octeon-core.c               |  46 +-
 drivers/i2c/busses/i2c-pxa-pci.c                   |  32 +-
 drivers/i2c/busses/i2c-pxa.c                       |  26 +-
 drivers/i2c/busses/i2c-qup.c                       | 122 +++-
 drivers/i2c/busses/i2c-rcar.c                      |   5 +-
 drivers/i2c/busses/i2c-sh_mobile.c                 |   4 +-
 drivers/i2c/busses/i2c-uniphier-f.c                |   6 +-
 drivers/i2c/busses/i2c-uniphier.c                  |   6 +-
 drivers/i2c/busses/i2c-viperboard.c                |   2 +-
 drivers/i2c/busses/i2c-xlp9xx.c                    |   1 +
 drivers/i2c/i2c-core.c                             | 197 ++++++-
 drivers/i2c/i2c-smbus.c                            | 102 ----
 drivers/i2c/muxes/Kconfig                          |  11 +
 drivers/i2c/muxes/Makefile                         |   1 +
 drivers/i2c/muxes/i2c-mux-gpio.c                   |  18 +-
 drivers/i2c/muxes/i2c-mux-mlxcpld.c                | 220 +++++++
 drivers/i2c/muxes/i2c-mux-pca954x.c                |  28 +-
 drivers/mfd/88pm860x-core.c                        |   5 +-
 include/linux/i2c-smbus.h                          |  27 -
 include/linux/i2c.h                                |  26 +-
 include/linux/i2c/mlxcpld.h                        |  52 ++
 42 files changed, 2264 insertions(+), 429 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/i2c/i2c-imx-lpi2c.txt
 create mode 100644 Documentation/i2c/busses/i2c-mlxcpld
 create mode 100644 drivers/i2c/busses/i2c-imx-lpi2c.c
 create mode 100644 drivers/i2c/busses/i2c-mlxcpld.c
 create mode 100644 drivers/i2c/muxes/i2c-mux-mlxcpld.c
 create mode 100644 include/linux/i2c/mlxcpld.h

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply

* Re: [PATCH v6 2/5] i2c: Add STM32F4 I2C driver
From: Wolfram Sang @ 2016-12-15 19:42 UTC (permalink / raw)
  To: Uwe Kleine-König
  Cc: M'boumba Cedric Madianga, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
	mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w,
	alexandre.torgue-qxv4g6HH51o,
	linus.walleij-QSEj5FYQhm4dnm+yROfE0A, patrice.chotard-qxv4g6HH51o,
	linux-I+IVW8TIWO2tmTQ+vhA3Yw, linux-i2c-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <20161213092031.d2ax2pnpzzicriel-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>

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


> > +	if (ret) {
> > +		dev_err(i2c_dev->dev, "bus not free\n");
> > +		ret = -EBUSY;
> 
> I'm not sure if "bus not free" deserves an error message. Wolfram?

I tend to agree. But I never enforced it up to now, never found the time
to double check if I could/should enforce it.


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply

* Re: [PATCH v6 2/5] i2c: Add STM32F4 I2C driver
From: Wolfram Sang @ 2016-12-15 19:40 UTC (permalink / raw)
  To: Uwe Kleine-König
  Cc: devicetree, Alexandre Torgue, linux-kernel, Linus Walleij,
	Patrice Chotard, linux, Rob Herring, linux-i2c, Maxime Coquelin,
	M'boumba Cedric Madianga, linux-arm-kernel
In-Reply-To: <20161215193307.436sggu4zy4zezoe@pengutronix.de>


[-- Attachment #1.1: Type: text/plain, Size: 395 bytes --]


> I thought (but I could be wrong) that if the driver is called
> "stm32f4-i2c", it is used to match "st,stm32f4-i2c" even without
> .of_match_table. If this doesn't work, please disregard my question.

This currently works only for *i2c client drivers*, it never did for i2c
adapters. And even for clients, this behaviour is going to be deprecated
somewhen. There are people working on it...


[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

[-- Attachment #2: Type: text/plain, Size: 176 bytes --]

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* Re: [PATCH v6 2/5] i2c: Add STM32F4 I2C driver
From: Uwe Kleine-König @ 2016-12-15 19:33 UTC (permalink / raw)
  To: M'boumba Cedric Madianga
  Cc: Wolfram Sang, Rob Herring, Maxime Coquelin, Alexandre Torgue,
	Linus Walleij, Patrice Chotard, linux, linux-i2c, devicetree,
	linux-arm-kernel, linux-kernel
In-Reply-To: <CAOAejn0Ej90amOZUC2wGNBsTAZVmcqEaViV1-TeoaspiADBkkg@mail.gmail.com>

Hello Cedric,

On Thu, Dec 15, 2016 at 04:26:25PM +0100, M'boumba Cedric Madianga wrote:
> >> +static struct platform_driver stm32f4_i2c_driver = {
> >> +     .driver = {
> >> +             .name = "stm32f4-i2c",
> >> +             .of_match_table = stm32f4_i2c_match,
> >
> > Is this needed?
> Without of_match_table, I could not match an I2C device instance from
> DT with this driver.
> So maybe, there is a misunderstanding.
> Could you please clarify your question ?

I thought (but I could be wrong) that if the driver is called
"stm32f4-i2c", it is used to match "st,stm32f4-i2c" even without
.of_match_table. If this doesn't work, please disregard my question.

Best regards
Uwe

-- 
Pengutronix e.K.                           | Uwe Kleine-König            |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |

^ permalink raw reply

* Re: [PATCH V5] i2c: designware: fix wrong Tx/Rx FIFO for ACPI
From: Andy Shevchenko @ 2016-12-15 17:57 UTC (permalink / raw)
  To: Tin Huynh, Jarkko Nikula, Mika Westerberg, Wolfram Sang
  Cc: linux-i2c, linux-kernel, linux-acpi, Loc Ho, Thang Nguyen,
	Phong Vo, patches
In-Reply-To: <1481707438-32240-1-git-send-email-tnhuynh@apm.com>

On Wed, 2016-12-14 at 16:23 +0700, Tin Huynh wrote:
> ACPI always sets Tx/Rx FIFO to 32. This configuration will
> cause problem if the IP core supports a FIFO size of less than 32.
> The driver should read the FIFO size from the IP and select the
> smaller
> one of the two.
> 
> Signed-off-by: Tin Huynh <tnhuynh@apm.com>
> 

Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>

> ---
>  drivers/i2c/busses/i2c-designware-platdrv.c |   31
> ++++++++++++++++++++------
>  1 files changed, 24 insertions(+), 7 deletions(-)
> 
> Change from V4:
>  -Change else condition and add some comments to clarify new approach.
> 
> Change from V3:
>  -Use uppercase of FIFO instead of lowercase.
>  -Correct else condition when IP core return 0 of FIFO.
> 
> Change from V2:
>  -Add a helper function to set FIFO size.
> 
> Change from V1:
>  -Revert the default 32 for FIFO, read parameter from IP core
>  and pick the smaller one of the two.
>  -Correct the title to describe new approach.
> 
> diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c
> b/drivers/i2c/busses/i2c-designware-platdrv.c
> index 0b42a12..682adc3 100644
> --- a/drivers/i2c/busses/i2c-designware-platdrv.c
> +++ b/drivers/i2c/busses/i2c-designware-platdrv.c
> @@ -150,6 +150,29 @@ static int i2c_dw_plat_prepare_clk(struct
> dw_i2c_dev *i_dev, bool prepare)
>  	return 0;
>  }
>  
> +static void dw_i2c_set_fifo_size(struct dw_i2c_dev *dev, int id)
> +{
> +	u32 param, tx_fifo_depth, rx_fifo_depth;
> +
> +	/*
> +	 * Try to detect the FIFO depth if not set by interface
> driver,
> +	 * the depth could be from 2 to 256 from HW spec.
> +	 */
> +	param = i2c_dw_read_comp_param(dev);
> +	tx_fifo_depth = ((param >> 16) & 0xff) + 1;
> +	rx_fifo_depth = ((param >> 8)  & 0xff) + 1;
> +	if (!dev->tx_fifo_depth) {
> +		dev->tx_fifo_depth = tx_fifo_depth;
> +		dev->rx_fifo_depth = rx_fifo_depth;
> +		dev->adapter.nr = id;
> +	} else if (tx_fifo_depth >= 2) {
> +		dev->tx_fifo_depth = min_t(u32, dev->tx_fifo_depth,
> +				tx_fifo_depth);
> +		dev->rx_fifo_depth = min_t(u32, dev->rx_fifo_depth,
> +				rx_fifo_depth);
> +	}
> +}
> +
>  static int dw_i2c_plat_probe(struct platform_device *pdev)
>  {
>  	struct dw_i2c_platform_data *pdata = dev_get_platdata(&pdev-
> >dev);
> @@ -246,13 +269,7 @@ static int dw_i2c_plat_probe(struct
> platform_device *pdev)
>  				1000000);
>  	}
>  
> -	if (!dev->tx_fifo_depth) {
> -		u32 param1 = i2c_dw_read_comp_param(dev);
> -
> -		dev->tx_fifo_depth = ((param1 >> 16) & 0xff) + 1;
> -		dev->rx_fifo_depth = ((param1 >> 8)  & 0xff) + 1;
> -		dev->adapter.nr = pdev->id;
> -	}
> +	dw_i2c_set_fifo_size(dev, pdev->id);
>  
>  	adap = &dev->adapter;
>  	adap->owner = THIS_MODULE;

-- 
Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Intel Finland Oy

^ permalink raw reply

* Re: [PATCH v2] i2c: designware: Cleaning and comment style fixes.
From: Peter Rosin @ 2016-12-15 15:17 UTC (permalink / raw)
  To: Luis Oliveira, wsa, robh+dt, mark.rutland, jarkko.nikula,
	andriy.shevchenko, mika.westerberg, linux-i2c, devicetree,
	linux-kernel
  Cc: Ramiro.Oliveira, Joao.Pinto, CARLOS.PALMINHA
In-Reply-To: <d7b5a22ce09539c2af343c21ca69675bef6a0a10.1481812563.git.lolivei@synopsys.com>

On 2016-12-15 15:38, Luis Oliveira wrote:
> diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h
> index 26250b425e2f..3cb81fca7738 100644
> --- a/drivers/i2c/busses/i2c-designware-core.h
> +++ b/drivers/i2c/busses/i2c-designware-core.h
> @@ -36,7 +36,7 @@
>  #define DW_IC_CON_SPEED_FAST		0x4
>  #define DW_IC_CON_SPEED_HIGH		0x6
>  #define DW_IC_CON_SPEED_MASK		0x6
> -#define DW_IC_CON_10BITADDR_MASTER	0x10
> +#define DW_IC_CON_10BITADDR_MASTER		0x10

How is this an improvement?

Cheers,
peda

^ permalink raw reply

* Re: [PATCH v2] i2c: designware: Cleaning and comment style fixes.
From: Luis Oliveira @ 2016-12-15 15:53 UTC (permalink / raw)
  To: Peter Rosin, Luis Oliveira, wsa-z923LK4zBo2bacvFa/9K2g,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
	jarkko.nikula-VuQAYsv1563Yd54FQh9/CA,
	andriy.shevchenko-VuQAYsv1563Yd54FQh9/CA,
	mika.westerberg-VuQAYsv1563Yd54FQh9/CA,
	linux-i2c-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA
  Cc: Ramiro.Oliveira-HKixBCOQz3hWk0Htik3J/w,
	Joao.Pinto-HKixBCOQz3hWk0Htik3J/w,
	CARLOS.PALMINHA-HKixBCOQz3hWk0Htik3J/w
In-Reply-To: <f11794ec-439b-5fcd-65f4-c14c319cd627-koto5C5qi+TLoDKTGw+V6w@public.gmane.org>

On 15-Dec-16 15:17, Peter Rosin wrote:
> On 2016-12-15 15:38, Luis Oliveira wrote:
>> diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h
>> index 26250b425e2f..3cb81fca7738 100644
>> --- a/drivers/i2c/busses/i2c-designware-core.h
>> +++ b/drivers/i2c/busses/i2c-designware-core.h
>> @@ -36,7 +36,7 @@
>>  #define DW_IC_CON_SPEED_FAST		0x4
>>  #define DW_IC_CON_SPEED_HIGH		0x6
>>  #define DW_IC_CON_SPEED_MASK		0x6
>> -#define DW_IC_CON_10BITADDR_MASTER	0x10
>> +#define DW_IC_CON_10BITADDR_MASTER		0x10
> 
> How is this an improvement?

It is not, I will fix it.

Thanks,
Luis
> 
> Cheers,
> peda
> 

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH 5/5] mfd: axp20x: Fix axp288 volatile ranges
From: Hans de Goede @ 2016-12-15 15:44 UTC (permalink / raw)
  To: Chen-Yu Tsai; +Cc: Lee Jones, russianneuromancer @ ya . ru, linux-i2c
In-Reply-To: <CAGb2v66Wd06foGn3dxaVrTYZrfhwox0Mc1YB=jM5+Z87UWXMrg@mail.gmail.com>

Hi,

On 14-12-16 15:41, Chen-Yu Tsai wrote:
> On Wed, Dec 14, 2016 at 9:52 PM, Hans de Goede <hdegoede@redhat.com> wrote:
>> The axp288 pmic has a lot more volatile registers then we were
>> listing in axp288_volatile_ranges, fix this.
>>
>> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
>> ---
>>  drivers/mfd/axp20x.c | 3 +++
>>  1 file changed, 3 insertions(+)
>>
>> diff --git a/drivers/mfd/axp20x.c b/drivers/mfd/axp20x.c
>> index a294121..b9c1adf 100644
>> --- a/drivers/mfd/axp20x.c
>> +++ b/drivers/mfd/axp20x.c
>> @@ -117,7 +117,10 @@ static const struct regmap_range axp288_writeable_ranges[] = {
>>  };
>>
>>  static const struct regmap_range axp288_volatile_ranges[] = {
>> +       regmap_reg_range(AXP20X_PWR_INPUT_STATUS, AXP20X_PWR_OP_MODE),
>
> Actually register 0x02 is volatile as well. Various fields say "write
> 1 to clear".
> You might need a new define for it though, as the usage is different.
>
>>         regmap_reg_range(AXP20X_IRQ1_EN, AXP20X_IPSOUT_V_HIGH_L),
>> +       regmap_reg_range(AXP22X_GPIO_STATE, AXP22X_GPIO_STATE),
>> +       regmap_reg_range(AXP20X_FG_RES, AXP288_FG_CC_CAP_REG),
>
> Could you also add AXP20X_TIMER_CTRL and 0xa0 ~ 0xa1 (real time
> battery voltage),
> if you're adding defines?

We also need to add 0xbc "BC Detect Status Register" to be able
to get the results of the charger detect logic in the axp288.

Self-nak for v2, I will send a v3 later.

Regards,

Hans

^ permalink raw reply

* Re: [PATCH v2] i2c: designware: add reset interface
From: Jarkko Nikula @ 2016-12-15 15:40 UTC (permalink / raw)
  To: Phil Reid, Andy Shevchenko, Zhangfei Gao, Wolfram Sang,
	mika.westerberg
  Cc: linux-i2c, linux-arm-kernel
In-Reply-To: <66e86b18-c6d5-4290-5e93-dcae50596da6@electromag.com.au>

On 12/15/2016 04:11 PM, Phil Reid wrote:
> On 15/12/2016 20:33, Andy Shevchenko wrote:
>> On Thu, 2016-12-15 at 16:59 +0800, Zhangfei Gao wrote:
>>> Some platforms like hi3660 need do reset first to allow accessing
>>> registers
>>
>> Patch itself looks good, but would be nice to have it tested.
>>
>> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
>>
>>>
>>> Signed-off-by: Zhangfei Gao <zhangfei.gao@linaro.org>
>>> ---
>>>  drivers/i2c/busses/i2c-designware-core.h    |  1 +
>>>  drivers/i2c/busses/i2c-designware-platdrv.c | 28
>>> ++++++++++++++++++++++++----
>>>  2 files changed, 25 insertions(+), 4 deletions(-)
>>>
>>> diff --git a/drivers/i2c/busses/i2c-designware-core.h
>>> b/drivers/i2c/busses/i2c-designware-core.h
>>> index 0d44d2a..94b14fa 100644
>>> --- a/drivers/i2c/busses/i2c-designware-core.h
>>> +++ b/drivers/i2c/busses/i2c-designware-core.h
>>> @@ -80,6 +80,7 @@ struct dw_i2c_dev {
>>>      void __iomem        *base;
>>>      struct completion    cmd_complete;
>>>      struct clk        *clk;
>>> +    struct reset_control    *rst;
>>>      u32            (*get_clk_rate_khz) (struct
>>> dw_i2c_dev *dev);
>>>      struct dw_pci_controller *controller;
>>>      int            cmd_err;
>>> diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c
>>> b/drivers/i2c/busses/i2c-designware-platdrv.c
>>> index 0b42a12..e9016ae 100644
>>> --- a/drivers/i2c/busses/i2c-designware-platdrv.c
>>> +++ b/drivers/i2c/busses/i2c-designware-platdrv.c
>>> @@ -38,6 +38,7 @@
>>>  #include <linux/pm_runtime.h>
>>>  #include <linux/property.h>
>>>  #include <linux/io.h>
>>> +#include <linux/reset.h>
>>>  #include <linux/slab.h>
>>>  #include <linux/acpi.h>
>>>  #include <linux/platform_data/i2c-designware.h>
>>> @@ -176,6 +177,14 @@ static int dw_i2c_plat_probe(struct
>>> platform_device *pdev)
>>>      dev->irq = irq;
>>>      platform_set_drvdata(pdev, dev);
>>>
>>> +    dev->rst = devm_reset_control_get_optional(&pdev->dev, NULL);
>>> +    if (IS_ERR(dev->rst)) {
>>> +        if (PTR_ERR(dev->rst) == -EPROBE_DEFER)
>>> +            return -EPROBE_DEFER;
>>> +    } else {
>>> +        reset_control_deassert(dev->rst);
>>> +    }
>>> +
> More for my education. But some drivers seem to handle the error codes a
> little more explicitly.
> Whats the best approach?
>
> eg: From usb/dwc2 driver it continues only if ENOENT / ENOTSUPP errors
> are return
> and ENOMEM / EINVAL etc is a fatal error.
>
> hsotg->reset = devm_reset_control_get_optional(hsotg->dev, "dwc2");
> if (IS_ERR(hsotg->reset)) {
>         ret = PTR_ERR(hsotg->reset);
>         switch (ret) {
>         case -ENOENT:
>         case -ENOTSUPP:
>                 hsotg->reset = NULL;
>                 break;
>         default:
>                 dev_err(hsotg->dev, "error getting reset control %d\n",
>                         ret);
>                 return ret;
>         }

This looks a bit extreme. At least we shouldn't spam log on machines 
that don't need reset control. I kind of think it's good enough to do 
like the patch does. I.e. handle only EPROBE_DEFER and let all other 
errors fall through and keep the controller in reset and let the 
dev->rst carry an error code.

I guess EINVAL is likely seen by developer only. ENOMEM is so fatal that 
things are already falling apart somewhere else too and I don't think it 
needs special handling here.

-- 
Jarkko

^ permalink raw reply

* Re: [PATCH v2] i2c: designware: add reset interface
From: Ramiro Oliveira @ 2016-12-15 15:30 UTC (permalink / raw)
  To: Andy Shevchenko, Zhangfei Gao, Wolfram Sang,
	mika.westerberg@linux.intel.com, jarkko.nikula@linux.intel.com
  Cc: linux-arm-kernel@lists.infradead.org, linux-i2c@vger.kernel.org
In-Reply-To: <1481805227.9552.15.camel@linux.intel.com>

Hi Andy and Zhangfei

On 12/15/2016 12:33 PM, Andy Shevchenko wrote:
> On Thu, 2016-12-15 at 16:59 +0800, Zhangfei Gao wrote:
>> Some platforms like hi3660 need do reset first to allow accessing
>> registers
> 
> Patch itself looks good, but would be nice to have it tested.
> 
> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
> 

I tested the patch and it's working for the ARC architecture.

>>
>> Signed-off-by: Zhangfei Gao <zhangfei.gao@linaro.org>
>> ---
>>  drivers/i2c/busses/i2c-designware-core.h    |  1 +
>>  drivers/i2c/busses/i2c-designware-platdrv.c | 28
>> ++++++++++++++++++++++++----
>>  2 files changed, 25 insertions(+), 4 deletions(-)
>>
>> diff --git a/drivers/i2c/busses/i2c-designware-core.h
>> b/drivers/i2c/busses/i2c-designware-core.h
>> index 0d44d2a..94b14fa 100644
>> --- a/drivers/i2c/busses/i2c-designware-core.h
>> +++ b/drivers/i2c/busses/i2c-designware-core.h
>> @@ -80,6 +80,7 @@ struct dw_i2c_dev {
>>  	void __iomem		*base;
>>  	struct completion	cmd_complete;
>>  	struct clk		*clk;
>> +	struct reset_control	*rst;
>>  	u32			(*get_clk_rate_khz) (struct
>> dw_i2c_dev *dev);
>>  	struct dw_pci_controller *controller;
>>  	int			cmd_err;
>> diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c
>> b/drivers/i2c/busses/i2c-designware-platdrv.c
>> index 0b42a12..e9016ae 100644
>> --- a/drivers/i2c/busses/i2c-designware-platdrv.c
>> +++ b/drivers/i2c/busses/i2c-designware-platdrv.c
>> @@ -38,6 +38,7 @@
>>  #include <linux/pm_runtime.h>
>>  #include <linux/property.h>
>>  #include <linux/io.h>
>> +#include <linux/reset.h>
>>  #include <linux/slab.h>
>>  #include <linux/acpi.h>
>>  #include <linux/platform_data/i2c-designware.h>
>> @@ -176,6 +177,14 @@ static int dw_i2c_plat_probe(struct
>> platform_device *pdev)
>>  	dev->irq = irq;
>>  	platform_set_drvdata(pdev, dev);
>>  
>> +	dev->rst = devm_reset_control_get_optional(&pdev->dev, NULL);

devm_reset_control_get_optional() is deprecated as explained in linux/reset.h,
you should use devm_reset_control_get_optional_exclusive() or
devm_reset_control_get_optional_shared() instead, as applicable.

I submitted a similar patch earlier today and I made the same mistake.

>> +	if (IS_ERR(dev->rst)) {
>> +		if (PTR_ERR(dev->rst) == -EPROBE_DEFER)
>> +			return -EPROBE_DEFER;
>> +	} else {
>> +		reset_control_deassert(dev->rst);
>> +	}
>> +
>>  	/* fast mode by default because of legacy reasons */
>>  	dev->clk_freq = 400000;
>>  
>> @@ -207,12 +216,13 @@ static int dw_i2c_plat_probe(struct
>> platform_device *pdev)
>>  	    && dev->clk_freq != 1000000 && dev->clk_freq != 3400000)
>> {
>>  		dev_err(&pdev->dev,
>>  			"Only 100kHz, 400kHz, 1MHz and 3.4MHz
>> supported");
>> -		return -EINVAL;
>> +		r = -EINVAL;
>> +		goto exit_reset;
>>  	}
>>  
>>  	r = i2c_dw_eval_lock_support(dev);
>>  	if (r)
>> -		return r;
>> +		goto exit_reset;
>>  
>>  	dev->functionality =
>>  		I2C_FUNC_I2C |
>> @@ -270,10 +280,18 @@ static int dw_i2c_plat_probe(struct
>> platform_device *pdev)
>>  	}
>>  
>>  	r = i2c_dw_probe(dev);
>> -	if (r && !dev->pm_runtime_disabled)
>> -		pm_runtime_disable(&pdev->dev);
>> +	if (r)
>> +		goto exit_probe;
>>  
>>  	return r;
>> +
>> +exit_probe:
>> +	if (!dev->pm_runtime_disabled)
>> +		pm_runtime_disable(&pdev->dev);
>> +exit_reset:
>> +	if (!IS_ERR_OR_NULL(dev->rst))
>> +		reset_control_assert(dev->rst);
>> +	return r;
>>  }
>>  
>>  static int dw_i2c_plat_remove(struct platform_device *pdev)
>> @@ -290,6 +308,8 @@ static int dw_i2c_plat_remove(struct
>> platform_device *pdev)
>>  	pm_runtime_put_sync(&pdev->dev);
>>  	if (!dev->pm_runtime_disabled)
>>  		pm_runtime_disable(&pdev->dev);
>> +	if (!IS_ERR_OR_NULL(dev->rst))
>> +		reset_control_assert(dev->rst);
>>  
>>  	return 0;
>>  }
> 
Tested-by: Ramiro Oliveira <ramiro.oliveira@synopsys.com>

^ permalink raw reply

* Re: [PATCH v6 2/5] i2c: Add STM32F4 I2C driver
From: M'boumba Cedric Madianga @ 2016-12-15 15:26 UTC (permalink / raw)
  To: Uwe Kleine-König
  Cc: devicetree, Alexandre Torgue, Wolfram Sang, linux-kernel,
	Linus Walleij, Patrice Chotard, linux, Rob Herring, linux-i2c,
	Maxime Coquelin, linux-arm-kernel
In-Reply-To: <20161213092031.d2ax2pnpzzicriel@pengutronix.de>

Hello,

Thanks for this review, it will help.

2016-12-13 10:20 GMT+01:00 Uwe Kleine-König <u.kleine-koenig@pengutronix.de>:
> Hello,
>
> On Mon, Dec 12, 2016 at 05:15:39PM +0100, M'boumba Cedric Madianga wrote:
>> This patch adds support for the STM32F4 I2C controller.
>>
>> Signed-off-by: M'boumba Cedric Madianga <cedric.madianga@gmail.com>
>> ---
>>  drivers/i2c/busses/Kconfig       |  10 +
>>  drivers/i2c/busses/Makefile      |   1 +
>>  drivers/i2c/busses/i2c-stm32f4.c | 849 +++++++++++++++++++++++++++++++++++++++
>>  3 files changed, 860 insertions(+)
>>  create mode 100644 drivers/i2c/busses/i2c-stm32f4.c
>>
>> diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
>> index 0cdc844..2719208 100644
>> --- a/drivers/i2c/busses/Kconfig
>> +++ b/drivers/i2c/busses/Kconfig
>> @@ -886,6 +886,16 @@ config I2C_ST
>>         This driver can also be built as module. If so, the module
>>         will be called i2c-st.
>>
>> +config I2C_STM32F4
>> +     tristate "STMicroelectronics STM32F4 I2C support"
>> +     depends on ARCH_STM32 || COMPILE_TEST
>> +     help
>> +       Enable this option to add support for STM32 I2C controller embedded
>> +       in STM32F4 SoCs.
>> +
>> +       This driver can also be built as module. If so, the module
>> +       will be called i2c-stm32f4.
>> +
>>  config I2C_STU300
>>       tristate "ST Microelectronics DDC I2C interface"
>>       depends on MACH_U300
>> diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
>> index 1c1bac8..a2c6ff5 100644
>> --- a/drivers/i2c/busses/Makefile
>> +++ b/drivers/i2c/busses/Makefile
>> @@ -85,6 +85,7 @@ obj-$(CONFIG_I2C_SH_MOBILE) += i2c-sh_mobile.o
>>  obj-$(CONFIG_I2C_SIMTEC)     += i2c-simtec.o
>>  obj-$(CONFIG_I2C_SIRF)               += i2c-sirf.o
>>  obj-$(CONFIG_I2C_ST)         += i2c-st.o
>> +obj-$(CONFIG_I2C_STM32F4)    += i2c-stm32f4.o
>>  obj-$(CONFIG_I2C_STU300)     += i2c-stu300.o
>>  obj-$(CONFIG_I2C_SUN6I_P2WI) += i2c-sun6i-p2wi.o
>>  obj-$(CONFIG_I2C_TEGRA)              += i2c-tegra.o
>> diff --git a/drivers/i2c/busses/i2c-stm32f4.c b/drivers/i2c/busses/i2c-stm32f4.c
>> new file mode 100644
>> index 0000000..89ad579
>> --- /dev/null
>> +++ b/drivers/i2c/busses/i2c-stm32f4.c
>> @@ -0,0 +1,849 @@
>> +/*
>> + * Driver for STMicroelectronics STM32 I2C controller
>> + *
>> + * Copyright (C) M'boumba Cedric Madianga 2015
>> + * Author: M'boumba Cedric Madianga <cedric.madianga@gmail.com>
>> + *
>> + * This driver is based on i2c-st.c
>> + *
>> + * License terms:  GNU General Public License (GPL), version 2
>> + */
>
> If there is a public description available for the device, a link here
> would be great.
The device is described in the reference manual of the STM32F429/439 SoC.
As this reference manual is public, I will add it at the beginning of
the driver as requested.

>
>> +
>> +#include <linux/clk.h>
>> +#include <linux/delay.h>
>> +#include <linux/err.h>
>> +#include <linux/i2c.h>
>> +#include <linux/interrupt.h>
>> +#include <linux/io.h>
>> +#include <linux/iopoll.h>
>> +#include <linux/module.h>
>> +#include <linux/of_address.h>
>> +#include <linux/of_irq.h>
>> +#include <linux/of.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/reset.h>
>> +
>> +/* STM32F4 I2C offset registers */
>> +#define STM32F4_I2C_CR1                      0x00
>> +#define STM32F4_I2C_CR2                      0x04
>> +#define STM32F4_I2C_DR                       0x10
>> +#define STM32F4_I2C_SR1                      0x14
>> +#define STM32F4_I2C_SR2                      0x18
>> +#define STM32F4_I2C_CCR                      0x1C
>> +#define STM32F4_I2C_TRISE            0x20
>> +#define STM32F4_I2C_FLTR             0x24
>> +
>> +/* STM32F4 I2C control 1*/
>> +#define STM32F4_I2C_CR1_SWRST                BIT(15)
>> +#define STM32F4_I2C_CR1_POS          BIT(11)
>> +#define STM32F4_I2C_CR1_ACK          BIT(10)
>> +#define STM32F4_I2C_CR1_STOP         BIT(9)
>> +#define STM32F4_I2C_CR1_START                BIT(8)
>> +#define STM32F4_I2C_CR1_PE           BIT(0)
>> +
>> +/* STM32F4 I2C control 2 */
>> +#define STM32F4_I2C_CR2_FREQ_MASK    GENMASK(5, 0)
>> +#define STM32F4_I2C_CR2_FREQ(n)              ((n & STM32F4_I2C_CR2_FREQ_MASK))
>
> This should better be ((n) & STM32F4_I2C_CR2_FREQ_MASK). There a few
> more constants that need the same fix.
OK I will fix it in the V7. Thanks.

>
>> +#define STM32F4_I2C_CR2_ITBUFEN              BIT(10)
>> +#define STM32F4_I2C_CR2_ITEVTEN              BIT(9)
>> +#define STM32F4_I2C_CR2_ITERREN              BIT(8)
>> +#define STM32F4_I2C_CR2_IRQ_MASK     (STM32F4_I2C_CR2_ITBUFEN \
>> +                                     | STM32F4_I2C_CR2_ITEVTEN \
>> +                                     | STM32F4_I2C_CR2_ITERREN)
>
> I'd layout this like:
>
>         #define STM32F4_I2C_CR2_IRQ_MASK        (STM32F4_I2C_CR2_ITBUFEN | \
>                                                  STM32F4_I2C_CR2_ITEVTEN | \
>                                                  STM32F4_I2C_CR2_ITERREN)
>
> which is more usual I think.
OK I will fix it in the V7. Thanks.

>
>> +/* STM32F4 I2C Status 1 */
>> +#define STM32F4_I2C_SR1_AF           BIT(10)
>> +#define STM32F4_I2C_SR1_ARLO         BIT(9)
>> +#define STM32F4_I2C_SR1_BERR         BIT(8)
>> +#define STM32F4_I2C_SR1_TXE          BIT(7)
>> +#define STM32F4_I2C_SR1_RXNE         BIT(6)
>> +#define STM32F4_I2C_SR1_BTF          BIT(2)
>> +#define STM32F4_I2C_SR1_ADDR         BIT(1)
>> +#define STM32F4_I2C_SR1_SB           BIT(0)
>> +#define STM32F4_I2C_SR1_ITEVTEN_MASK (STM32F4_I2C_SR1_BTF \
>> +                                     | STM32F4_I2C_SR1_ADDR \
>> +                                     | STM32F4_I2C_SR1_SB)
>> +#define STM32F4_I2C_SR1_ITBUFEN_MASK (STM32F4_I2C_SR1_TXE \
>> +                                     | STM32F4_I2C_SR1_RXNE)
>> +#define STM32F4_I2C_SR1_ITERREN_MASK (STM32F4_I2C_SR1_AF \
>> +                                     | STM32F4_I2C_SR1_ARLO \
>> +                                     | STM32F4_I2C_SR1_BERR)
>> +
>> +/* STM32F4 I2C Status 2 */
>> +#define STM32F4_I2C_SR2_BUSY         BIT(1)
>> +
>> +/* STM32F4 I2C Control Clock */
>> +#define STM32F4_I2C_CCR_CCR_MASK     GENMASK(11, 0)
>> +#define STM32F4_I2C_CCR_CCR(n)               ((n & STM32F4_I2C_CCR_CCR_MASK))
>> +#define STM32F4_I2C_CCR_FS           BIT(15)
>> +#define STM32F4_I2C_CCR_DUTY         BIT(14)
>> +
>> +/* STM32F4 I2C Trise */
>> +#define STM32F4_I2C_TRISE_VALUE_MASK GENMASK(5, 0)
>> +#define STM32F4_I2C_TRISE_VALUE(n)   ((n & STM32F4_I2C_TRISE_VALUE_MASK))
>> +
>> +/* STM32F4 I2C Filter */
>> +#define STM32F4_I2C_FLTR_DNF_MASK    GENMASK(3, 0)
>> +#define STM32F4_I2C_FLTR_DNF(n)              ((n & STM32F4_I2C_FLTR_DNF_MASK))
>> +#define STM32F4_I2C_FLTR_ANOFF               BIT(4)
>> +
>> +#define STM32F4_I2C_MIN_FREQ         2U
>> +#define STM32F4_I2C_MAX_FREQ         42U
>> +#define FAST_MODE_MAX_RISE_TIME              1000
>> +#define STD_MODE_MAX_RISE_TIME               300
>
> Are these supposed to be the values "rise time of both SDA and SCL
> signals" from the i2c specification? If so, you got it wrong, fast mode
> has the smaller value.
Yes you are right. My mistake. Thanks

> Maybe these constants could get a home in a more central place?
Yes we probably could add these constants in a include file like i2c.h
or someting like that.
Wolfram, what is your opinion regarding this proposal ?

> Also I'd add /* ns */ to the definition.
Ok

>
>> +#define MHZ_TO_HZ                    1000000
>> +
>> +enum stm32f4_i2c_speed {
>> +     STM32F4_I2C_SPEED_STANDARD, /* 100 kHz */
>> +     STM32F4_I2C_SPEED_FAST, /* 400 kHz */
>> +     STM32F4_I2C_SPEED_END,
>> +};
>> +
>> +/**
>> + * struct stm32f4_i2c_timings - per-Mode tuning parameters
>> + * @duty: Fast mode duty cycle
>> + * @mul_ccr: Value to be multiplied to CCR to reach 100Khz/400Khz SCL frequency
>> + * @min_ccr: Minimum clock ctrl reg value to reach 100Khz/400Khz SCL frequency
>> + */
>> +struct stm32f4_i2c_timings {
>> +     u32 rate;
>
> rate is undocumented and unused.
Good point. I will remove it. Thanks.

>
>> +     u32 duty;
>> +     u32 mul_ccr;
>> +     u32 min_ccr;
>> +};
>> +
>> +/**
>> + * struct stm32f4_i2c_msg - client specific data
>> + * @addr: 8-bit slave addr, including r/w bit
>> + * @count: number of bytes to be transferred
>> + * @buf: data buffer
>> + * @result: result of the transfer
>> + * @stop: last I2C msg to be sent, i.e. STOP to be generated
>> + */
>> +struct stm32f4_i2c_msg {
>> +     u8      addr;
>> +     u32     count;
>> +     u8      *buf;
>> +     int     result;
>> +     bool    stop;
>> +};
>> +
>> +/**
>> + * struct stm32f4_i2c_dev - private data of the controller
>> + * @adap: I2C adapter for this controller
>> + * @dev: device for this controller
>> + * @base: virtual memory area
>> + * @complete: completion of I2C message
>> + * @irq_event: interrupt event line for the controller
>> + * @irq_error: interrupt error line for the controller
>> + * @clk: hw i2c clock
>> + * speed: I2C clock frequency of the controller. Standard or Fast only supported
>> + * @msg: I2C transfer information
>> + */
>> +struct stm32f4_i2c_dev {
>> +     struct i2c_adapter              adap;
>> +     struct device                   *dev;
>> +     void __iomem                    *base;
>> +     struct completion               complete;
>> +     int                             irq_event;
>> +     int                             irq_error;
>
> You only use irq_event in the probe function. So there is no need to
> remember this one and you could use a local variable instead.
Ok, I will fix it in the V7. Thanks

>
>> +     struct clk                      *clk;
>> +     int                             speed;
>> +     struct stm32f4_i2c_msg          msg;
>> +};
>> +
>> +static struct stm32f4_i2c_timings i2c_timings[] = {
>> +     [STM32F4_I2C_SPEED_STANDARD] = {
>> +             .mul_ccr                = 1,
>> +             .min_ccr                = 4,
>> +             .duty                   = 0,
>> +     },
>> +     [STM32F4_I2C_SPEED_FAST] = {
>> +             .mul_ccr                = 16,
>> +             .min_ccr                = 1,
>> +             .duty                   = 1,
>> +     },
>
> Are these values from the datasheet?
Yes, these values come from I2C IP datasheet.

>
>> +};
>> +
>> +static inline void stm32f4_i2c_set_bits(void __iomem *reg, u32 mask)
>> +{
>> +     writel_relaxed(readl_relaxed(reg) | mask, reg);
>> +}
>> +
>> +static inline void stm32f4_i2c_clr_bits(void __iomem *reg, u32 mask)
>> +{
>> +     writel_relaxed(readl_relaxed(reg) & ~mask, reg);
>> +}
>> +
>> +static void stm32f4_i2c_soft_reset(struct stm32f4_i2c_dev *i2c_dev)
>> +{
>> +     void __iomem *reg = i2c_dev->base + STM32F4_I2C_CR1;
>> +
>> +     stm32f4_i2c_set_bits(reg, STM32F4_I2C_CR1_SWRST);
>> +     stm32f4_i2c_clr_bits(reg, STM32F4_I2C_CR1_SWRST);
>
> Not very critical, but you're doing an unneeded register access here
> because the register is read twice.
>
> Also I think readability would improve if you dropped
> stm32f4_i2c_{set,clr}_bits and do their logic explicitly in the callers.
>
>         stm32f4_i2c_set_bits(reg, STM32F4_I2C_CR1_SWRST);
>         stm32f4_i2c_clr_bits(reg, STM32F4_I2C_CR1_SWRST);
>
> vs
>
>         val = readl_relaxed(reg);
>         writel_relaxed(val | STM32F4_I2C_CR1_SWRST, reg);
>         writel_relaxed(val, reg);
>
If it is just for this function, I don't have any objection to use
your proposal.
But if your request, it is to drop all calls of
stm32f4_i2c_{set,clr}_bits, I am wondering if it is something really
critical ?
Indeed, this is a big impact in this driver and I would prefer to avoid it.

>> +}
>> +
>> +static void stm32f4_i2c_disable_it(struct stm32f4_i2c_dev *i2c_dev)
>
> What is "it"? If it stands for "interrupt" the more usual abbrev is
> "irq".
Yes it stands for interrupt.
So, I will replace it by irq in the next version.

>
>> +{
>> +     void __iomem *reg = i2c_dev->base + STM32F4_I2C_CR2;
>> +
>> +     stm32f4_i2c_clr_bits(reg, STM32F4_I2C_CR2_IRQ_MASK);
>> +}
>> +
>> +static void stm32f4_i2c_set_periph_clk_freq(struct stm32f4_i2c_dev *i2c_dev)
>> +{
>> +     u32 clk_rate, cr2, freq;
>> +
>> +     cr2 = readl_relaxed(i2c_dev->base + STM32F4_I2C_CR2);
>> +     cr2 &= ~STM32F4_I2C_CR2_FREQ_MASK;
>> +     clk_rate = clk_get_rate(i2c_dev->clk);
>> +     freq = clk_rate / MHZ_TO_HZ;
>> +     freq = clamp(freq, STM32F4_I2C_MIN_FREQ, STM32F4_I2C_MAX_FREQ);
>> +     cr2 |= STM32F4_I2C_CR2_FREQ(freq);
>> +     writel_relaxed(cr2, i2c_dev->base + STM32F4_I2C_CR2);
>
> Can you quote the data sheet enough in a comment here to make it obvious
> that your calculation is right?
Ok I will add it.

>
> Would it be more sensible to error out if clk_rate / MHZ_TO_HZ isn't in
> the interval [STM32F4_I2C_MIN_FREQ, STM32F4_I2C_MAX_FREQ]?
Yes, input clock must be between 2 MHz and 42 Mhz to achieve standard
or fast mode mode I²C frequencies.
If it is not the case, the I2C signal integrity is not guarantee and
could lead to communication issue between devices on the I2C bus.

>
> Usually I would expect that you need to use
> DIV_ROUND_UP(clk_rate, MHZ_TO_HZ) instead of a plain division.
Ok, I will use this macro in the next version

>
>> +}
>> +
>> +static void stm32f4_i2c_set_rise_time(struct stm32f4_i2c_dev *i2c_dev)
>> +{
>> +     u32 trise, freq, cr2, val;
>> +
>> +     cr2 = readl_relaxed(i2c_dev->base + STM32F4_I2C_CR2);
>> +     freq = cr2 & STM32F4_I2C_CR2_FREQ_MASK;
>> +
>> +     trise = readl_relaxed(i2c_dev->base + STM32F4_I2C_TRISE);
>> +     trise &= ~STM32F4_I2C_TRISE_VALUE_MASK;
>
> Are you required to use rmw for STM32F4_I2C_TRISE? I'd prefer
>
>         writel_relaxed(STM32F4_I2C_TRISE_VALUE(..), i2c_dev->base + STM32F4_I2C_TRISE);
>
> unless the datasheet requires rmw.
>
>> +     /* Maximum rise time computation */
>> +     if (i2c_dev->speed == STM32F4_I2C_SPEED_STANDARD) {
>> +             trise |= STM32F4_I2C_TRISE_VALUE((freq + 1));
>
> A single pair of parenthesis is enough when you fix
> STM32F4_I2C_TRISE_VALUE as suggested above.
The datasheet does not required to use rmw so I will use your proposal
in the next version. Thanks.

>
>> +     } else {
>> +             val = freq * FAST_MODE_MAX_RISE_TIME / STD_MODE_MAX_RISE_TIME;
>> +             trise |= STM32F4_I2C_TRISE_VALUE((val + 1));
>
> val could be local to this branch.
>
> Or make it shorter using:
>
>         freq = cr2 & STM32F4_I2C_CR2_FREQ_MASK;
>         if (i2c_dev->speed == STM32F4_I2C_SPEED_FAST)
>                 freq = freq * FAST_MODE_MAX_RISE_TIME / STD_MODE_MAX_RISE_TIME;
>
>         writel_relaxed(STM32F4_I2C_TRISE_VALUE(freq + 1), ...);
>
> A quote from the data sheet about the algorithm would be good here, too.
Ok, I will use a shorter way to compute freq and add a quote from the datasheet

>
>> +     }
>> +
>> +     writel_relaxed(trise, i2c_dev->base + STM32F4_I2C_TRISE);
>> +}
>> +
>> +static void stm32f4_i2c_set_speed_mode(struct stm32f4_i2c_dev *i2c_dev)
>> +{
>> +     struct stm32f4_i2c_timings *t = &i2c_timings[i2c_dev->speed];
>> +     u32 ccr, clk_rate;
>> +     int val;
>> +
>> +     ccr = readl_relaxed(i2c_dev->base + STM32F4_I2C_CCR);
>> +     ccr &= ~(STM32F4_I2C_CCR_FS | STM32F4_I2C_CCR_DUTY |
>> +              STM32F4_I2C_CCR_CCR_MASK);
>> +
>> +     clk_rate = clk_get_rate(i2c_dev->clk);
>> +     val = clk_rate / MHZ_TO_HZ * t->mul_ccr;
>
> Is the rounding done right? Again please describe the hardware in a
> comment.
Ok I will use DIV_ROUND_UP here and add a comment from datasheet

>
>> +     if (val < t->min_ccr)
>> +             val = t->min_ccr;
>> +     ccr |= STM32F4_I2C_CCR_CCR(val);
>> +
>> +     if (t->duty)
>> +             ccr |= STM32F4_I2C_CCR_FS | STM32F4_I2C_CCR_DUTY;
>> +
>> +     writel_relaxed(ccr, i2c_dev->base + STM32F4_I2C_CCR);
>> +}
>> +[...]
>> +
>> +static int stm32f4_i2c_wait_free_bus(struct stm32f4_i2c_dev *i2c_dev)
>> +{
>> +     u32 status;
>> +     int ret;
>> +
>> +     ret = readl_relaxed_poll_timeout(i2c_dev->base + STM32F4_I2C_SR2,
>> +                                      status,
>> +                                      !(status & STM32F4_I2C_SR2_BUSY),
>> +                                      10, 1000);
>> +     if (ret) {
>> +             dev_err(i2c_dev->dev, "bus not free\n");
>> +             ret = -EBUSY;
>
> I'm not sure if "bus not free" deserves an error message. Wolfram?
>
>> +     }
>> +
>> +     return ret;
>> +}
>> +
>> +[...]
>> +static void stm32f4_i2c_read_msg(struct stm32f4_i2c_dev *i2c_dev)
>> +{
>> +     struct stm32f4_i2c_msg *msg = &i2c_dev->msg;
>> +     u32 rbuf;
>> +
>> +     rbuf = readl_relaxed(i2c_dev->base + STM32F4_I2C_DR);
>> +     *msg->buf++ = (u8)rbuf & 0xff;
>
> unneeded cast (or unneeded & 0xff).
Ok thanks

>
>> +     msg->count--;
>> +}
>> +
>> +[...]
>> +/**
>> + * stm32f4_i2c_handle_read() - Handle FIFO empty interrupt in case of read
>> + * @i2c_dev: Controller's private data
>> + */
>> +static void stm32f4_i2c_handle_read(struct stm32f4_i2c_dev *i2c_dev)
>> +{
>> +     struct stm32f4_i2c_msg *msg = &i2c_dev->msg;
>> +     void __iomem *reg = i2c_dev->base + STM32F4_I2C_CR2;
>> +
>> +     switch (msg->count) {
>> +     case 1:
>> +             stm32f4_i2c_disable_it(i2c_dev);
>> +             stm32f4_i2c_read_msg(i2c_dev);
>> +             complete(&i2c_dev->complete);
>> +             break;
>> +     case 2:
>> +     case 3:
>> +             stm32f4_i2c_clr_bits(reg, STM32F4_I2C_CR2_ITBUFEN);
>> +             break;
>> +     default:
>> +             stm32f4_i2c_read_msg(i2c_dev);
>> +     }
>
> It looks wrong that you don't call stm32f4_i2c_read_msg if msg->count is
> 2 or 3. I guess that's because these cases are handled in
> stm32f4_i2c_handle_rx_btf? Maybe you can simplify the logic a bit?
stm32f4_i2c_handle_read is called when RXNE bit is set due to new data
present in DR register.
stm32f4_i2c_handle_rx_btf is called when BTF bit is set.
This bit is set when there is new data in shift register whereas data
in DR register has not been read yet.
The datasheet requires to wait for BTF bit for 2 byte reception and
for the 3 last bytes to be read for N bytes reception (with N > 2)
That's why, in these cases (2 and 3), I clear the ITBUF interrupt in
order to not be preempted again for RXNE event as I know that I have
to wait for BTF event.
So, this is not a wrong case but I will add a comment to explain that.

>
>> +}
>> +
>> +/**
>> + * stm32f4_i2c_handle_rx_btf() - Handle byte transfer finished interrupt
>> + * in case of read
>> + * @i2c_dev: Controller's private data
>> + */
>> +static void stm32f4_i2c_handle_rx_btf(struct stm32f4_i2c_dev *i2c_dev)
>> +{
>> +     struct stm32f4_i2c_msg *msg = &i2c_dev->msg;
>> +     void __iomem *reg;
>> +     u32 mask;
>> +     int i;
>> +
>> +     switch (msg->count) {
>
> I don't understand why the handling depends on the number of messages.
Please see my above comment

>
>> +     case 2:
>> +             reg = i2c_dev->base + STM32F4_I2C_CR1;
>> +             /* Generate STOP or REPSTART */
>
> I stumbled about "REPSTART" and would spell it out as "repeated Start".
Ok

>
>> +             if (msg->stop)
>> +                     stm32f4_i2c_set_bits(reg, STM32F4_I2C_CR1_STOP);
>> +             else
>> +                     stm32f4_i2c_set_bits(reg, STM32F4_I2C_CR1_START);
>> +
>> +             /* Read two last data bytes */
>> +             for (i = 2; i > 0; i--)
>> +                     stm32f4_i2c_read_msg(i2c_dev);
>> +
>> +             /* Disable EVT and ERR interrupt */
>> +             reg = i2c_dev->base + STM32F4_I2C_CR2;
>> +             mask = STM32F4_I2C_CR2_ITEVTEN | STM32F4_I2C_CR2_ITERREN;
>> +             stm32f4_i2c_clr_bits(reg, mask);
>> +
>> +             complete(&i2c_dev->complete);
>> +             break;
>> +     case 3:
>> +             /* Enable ACK and read data */
>> +             reg = i2c_dev->base + STM32F4_I2C_CR1;
>> +             stm32f4_i2c_clr_bits(reg, STM32F4_I2C_CR1_ACK);
>> +             stm32f4_i2c_read_msg(i2c_dev);
>> +             break;
>> +     default:
>> +             stm32f4_i2c_read_msg(i2c_dev);
>> +     }
>> +}
>> +
>> +/**
>> + * stm32f4_i2c_handle_rx_addr() - Handle address matched interrupt in case of
>> + * master receiver
>> + * @i2c_dev: Controller's private data
>> + */
>> +static void stm32f4_i2c_handle_rx_addr(struct stm32f4_i2c_dev *i2c_dev)
>> +{
>> +     struct stm32f4_i2c_msg *msg = &i2c_dev->msg;
>> +     void __iomem *reg;
>> +
>> +     switch (msg->count) {
>> +     case 0:
>> +             stm32f4_i2c_terminate_xfer(i2c_dev);
>> +             /* Clear ADDR flag */
>> +             readl_relaxed(i2c_dev->base + STM32F4_I2C_SR2);
>> +             break;
>> +     case 1:
>> +             /*
>> +              * Single byte reception:
>> +              * Enable NACK, clear ADDR flag and generate STOP or RepSTART
>> +              */
>> +             reg = i2c_dev->base + STM32F4_I2C_CR1;
>> +             stm32f4_i2c_clr_bits(reg, STM32F4_I2C_CR1_ACK);
>> +             if (msg->stop)
>> +                     stm32f4_i2c_set_bits(reg, STM32F4_I2C_CR1_STOP);
>> +             else
>> +                     stm32f4_i2c_set_bits(reg, STM32F4_I2C_CR1_START);
>> +             break;
>> +     case 2:
>> +             /*
>> +              * 2-byte reception:
>> +              * Enable NACK and PEC Position Ack and clear ADDR flag
>
> What is PEC?
PEC stands for Packet Error Checking.
This feature is used is SMbus mode in order to guarantee data
integrity during an I2C transaction thanks to packet error code
comparaison.
The POS bit is used in reception to indicate that the next byte
received in the shift register will be ACK by hardware.
So, this is a wrong comment I would say POS ACK and I will fix it in
the next version.

>
>> +              */
>> +             reg = i2c_dev->base + STM32F4_I2C_CR1;
>> +             stm32f4_i2c_clr_bits(reg, STM32F4_I2C_CR1_ACK);
>> +             stm32f4_i2c_set_bits(reg, STM32F4_I2C_CR1_POS);
>> +             readl_relaxed(i2c_dev->base + STM32F4_I2C_SR2);
>> +             break;
>> +
>> +     default:
>> +             /* N-byte reception: Enable ACK and clear ADDR flag */
>> +             reg = i2c_dev->base + STM32F4_I2C_CR1;
>> +             stm32f4_i2c_set_bits(reg, STM32F4_I2C_CR1_ACK);
>> +             readl_relaxed(i2c_dev->base + STM32F4_I2C_SR2);
>> +             break;
>> +     }
>> +}
>> +
>> +/**
>> + * stm32f4_i2c_isr_event() - Interrupt routine for I2C bus event
>> + * @irq: interrupt number
>> + * @data: Controller's private data
>> + */
>> +static irqreturn_t stm32f4_i2c_isr_event(int irq, void *data)
>> +{
>> +[...]
>> +     real_status = readl_relaxed(i2c_dev->base + STM32F4_I2C_SR1);
>
> s/real_status/status/ ?
Ok. Thanks

>
>> +
>> +     if (!(real_status & possible_status)) {
>> +             dev_dbg(i2c_dev->dev,
>> +                     "spurious evt it (status=0x%08x, ien=0x%08x)\n",
>> +                     real_status, ien);
>
> s/it/irq/
Ok. Thanks

>
>> +             return IRQ_NONE;
>> +     }
>> +
>> +     /* Use __fls() to check error bits first */
>> +     flag = __fls(real_status & possible_status);
>
> If you get several events reported you only handle a single one. Is this
> effective?
You are right, if several events occur, I will execute this irq
routines for each event.
I will rework this in the next version. Thanks


>
>> +     switch (1 << flag) {
>> +     case STM32F4_I2C_SR1_SB:
>> +             stm32f4_i2c_write_byte(i2c_dev, msg->addr);
>> +             break;
>> +
>> +     case STM32F4_I2C_SR1_ADDR:
>> +             if (msg->addr & I2C_M_RD)
>> +                     stm32f4_i2c_handle_rx_addr(i2c_dev);
>> +             else
>> +                     readl_relaxed(i2c_dev->base + STM32F4_I2C_SR2);
>> +
>> +             /* Enable ITBUF interrupts */
>
> What is ITBUF?
ITBUF is an interrupt generated when RxNE or TxE flag is set

>
>> +             reg = i2c_dev->base + STM32F4_I2C_CR2;
>> +             stm32f4_i2c_set_bits(reg, STM32F4_I2C_CR2_ITBUFEN);
>> +             break;
>> +
>> +     case STM32F4_I2C_SR1_BTF:
>> +             if (msg->addr & I2C_M_RD)
>> +                     stm32f4_i2c_handle_rx_btf(i2c_dev);
>> +             else
>> +                     stm32f4_i2c_handle_write(i2c_dev);
>> +             break;
>> +
>> +     case STM32F4_I2C_SR1_TXE:
>> +             stm32f4_i2c_handle_write(i2c_dev);
>> +             break;
>> +
>> +     case STM32F4_I2C_SR1_RXNE:
>> +             stm32f4_i2c_handle_read(i2c_dev);
>> +             break;
>> +
>> +     default:
>> +             dev_err(i2c_dev->dev,
>> +                     "evt it unhandled: status=0x%08x)\n", real_status);
>
> s/it/irq/
ok

>
>> +             return IRQ_NONE;
>> +     }
>> +
>> +     return IRQ_HANDLED;
>> +}
>> +
>> +[...]
>> +static int stm32f4_i2c_xfer_msg(struct stm32f4_i2c_dev *i2c_dev,
>> +                             struct i2c_msg *msg, bool is_first,
>> +                             bool is_last)
>> +{
>> +[...]
>> +     /* Enable ITEVT and ITERR interrupts */
>
> This comment isn't helpful. Mentioning their meaning would be great
> instead.
ok I will add it (ITEVT = event interrupt and ITERR = error interrupt)

>
>> +[...]
>> +static int stm32f4_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[],
>> +                         int num)
>> +{
>> +     struct stm32f4_i2c_dev *i2c_dev = i2c_get_adapdata(i2c_adap);
>> +     int ret, i;
>> +
>> +     ret = clk_enable(i2c_dev->clk);
>> +     if (ret) {
>> +             dev_err(i2c_dev->dev, "Failed to enable clock\n");
>> +             return ret;
>> +     }
>> +
>> +     stm32f4_i2c_hw_config(i2c_dev);
>> +
>> +     for (i = 0; i < num && !ret; i++)
>> +             ret = stm32f4_i2c_xfer_msg(i2c_dev, &msgs[i], i == 0,
>> +                                        i == num - 1);
>> +
>> +     clk_disable(i2c_dev->clk);
>> +
>> +     return (ret < 0) ? ret : i;
>
> using num instead of i would be a bit more obvious.
ok

>
>> +static int stm32f4_i2c_probe(struct platform_device *pdev)
>> +{
>> +[...]
>> +     i2c_dev->speed = STM32F4_I2C_SPEED_STANDARD;
>> +     ret = of_property_read_u32(np, "clock-frequency", &clk_rate);
>> +     if ((!ret) && (clk_rate == 400000))
>> +             i2c_dev->speed = STM32F4_I2C_SPEED_FAST;
>
> I'd use
>
>         if (!ret && clk_rate >= 400000)
>                 i2c_dev->speed = STM32F4_I2C_SPEED_FAST;
>
> . That's less parenthesis and a more robust selection of the bus
> frequency.
ok

>
>> +
>> +     i2c_dev->dev = &pdev->dev;
>> +
>> +     ret = devm_request_threaded_irq(&pdev->dev, i2c_dev->irq_event,
>> +                                     NULL, stm32f4_i2c_isr_event,
>> +                                     IRQF_ONESHOT, pdev->name, i2c_dev);
>> +     if (ret) {
>> +             dev_err(&pdev->dev, "Failed to request irq %i\n",
>> +                     i2c_dev->irq_error);
>
> That's wrong. Requesting irq_event failed.
Ok Thanks.

>
>> +             goto clk_free;
>> +     }
>> +
>> +     ret = devm_request_threaded_irq(&pdev->dev, i2c_dev->irq_error,
>> +                                     NULL, stm32f4_i2c_isr_error,
>> +                                     IRQF_ONESHOT, pdev->name, i2c_dev);
>> +     if (ret) {
>> +             dev_err(&pdev->dev, "Failed to request irq %i\n",
>> +                     i2c_dev->irq_error);
>> +             goto clk_free;
>
> It would also be nice to know for which type of irq this failed. I.e.
> please point out if this is the error irq or the event irq in the
> message. Ditto for checking the return type of irq_of_parse_and_map.
Ok I will fix it in the next version.

>
>> +     }
>> +
>> +     adap = &i2c_dev->adap;
>> +     i2c_set_adapdata(adap, i2c_dev);
>> +     snprintf(adap->name, sizeof(adap->name), "STM32 I2C(%pa)", &res->start);
>> +     adap->owner = THIS_MODULE;
>> +     adap->timeout = 2 * HZ;
>> +     adap->retries = 0;
>> +     adap->algo = &stm32f4_i2c_algo;
>> +     adap->dev.parent = &pdev->dev;
>> +     adap->dev.of_node = pdev->dev.of_node;
>> +
>> +     init_completion(&i2c_dev->complete);
>> +
>> +     ret = i2c_add_adapter(adap);
>> +     if (ret)
>> +             goto clk_free;
>> +
>> +     platform_set_drvdata(pdev, i2c_dev);
>> +
>> +     dev_info(i2c_dev->dev, "STM32F4 I2C driver initialized\n");
>
> This is wrong. The driver is bound now to a device, not initialized.
Ok I will replaced initialized by registered. Thanks.

>
>> +static const struct of_device_id stm32f4_i2c_match[] = {
>> +     { .compatible = "st,stm32f4-i2c", },
>> +     {},
>> +};
>> +MODULE_DEVICE_TABLE(of, stm32f4_i2c_match);
>> +
>> +static struct platform_driver stm32f4_i2c_driver = {
>> +     .driver = {
>> +             .name = "stm32f4-i2c",
>> +             .of_match_table = stm32f4_i2c_match,
>
> Is this needed?
Without of_match_table, I could not match an I2C device instance from
DT with this driver.
So maybe, there is a misunderstanding.
Could you please clarify your question ?

>
>> +     },
>> +     .probe = stm32f4_i2c_probe,
>> +     .remove = stm32f4_i2c_remove,
>> +};
>
> Best regards
> Uwe
>
> --
> Pengutronix e.K.                           | Uwe Kleine-König            |
> Industrial Linux Solutions                 | http://www.pengutronix.de/  |

Thanks again
Best regards,

Cedric

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* [PATCH v3] i2c: designware: Cleaning and comment style fixes.
From: Luis Oliveira @ 2016-12-15 15:09 UTC (permalink / raw)
  To: wsa, robh+dt, mark.rutland, jarkko.nikula, andriy.shevchenko,
	mika.westerberg, linux-i2c, devicetree, linux-kernel
  Cc: Luis.Oliveira, Ramiro.Oliveira, Joao.Pinto, CARLOS.PALMINHA

The purpose of this commit is to fix some comments and styling issues in the
existing code due to the need of reuse this code. What is being made here is:

- Sorted the headers files
- Corrected some comments style
- Reverse tree in the variables declaration
- Add/remove empty lines and tabs where needed
- Fix of a misspelled word

The value of this, besides the rules of coding style, is because I
will use this code after and it will make my future patch a lot bigger and
complicated to review. The work here won't bring any additional work to
backported fixes because is just style and reordering.

Signed-off-by: Luis Oliveira <lolivei@synopsys.com>
---
Changes V2->V3: (Andy Shevchenko)
- Added the answers in the commit message.
- Added a comma, it seems to me it is the same sentence.
 
 drivers/i2c/busses/i2c-designware-core.c    | 36 ++++++++++++++---------------
 drivers/i2c/busses/i2c-designware-core.h    |  2 +-
 drivers/i2c/busses/i2c-designware-platdrv.c | 27 +++++++++++-----------
 3 files changed, 33 insertions(+), 32 deletions(-)

diff --git a/drivers/i2c/busses/i2c-designware-core.c b/drivers/i2c/busses/i2c-designware-core.c
index 6d81c56184d3..9d724a6a7ec8 100644
--- a/drivers/i2c/busses/i2c-designware-core.c
+++ b/drivers/i2c/busses/i2c-designware-core.c
@@ -21,17 +21,17 @@
  * ----------------------------------------------------------------------------
  *
  */
+#include <linux/delay.h>
 #include <linux/export.h>
 #include <linux/errno.h>
 #include <linux/err.h>
 #include <linux/i2c.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
-#include <linux/pm_runtime.h>
-#include <linux/delay.h>
 #include <linux/module.h>
-#include "i2c-designware-core.h"
+#include <linux/pm_runtime.h>
 
+#include "i2c-designware-core.h"
 /*
  * Registers offset
  */
@@ -98,7 +98,7 @@
 
 #define DW_IC_ERR_TX_ABRT	0x1
 
-#define DW_IC_TAR_10BITADDR_MASTER BIT(12)
+#define DW_IC_TAR_10BITADDR_MASTER		BIT(12)
 
 #define DW_IC_COMP_PARAM_1_SPEED_MODE_HIGH	(BIT(2) | BIT(3))
 #define DW_IC_COMP_PARAM_1_SPEED_MODE_MASK	GENMASK(3, 2)
@@ -113,10 +113,10 @@
 #define TIMEOUT			20 /* ms */
 
 /*
- * hardware abort codes from the DW_IC_TX_ABRT_SOURCE register
+ * Hardware abort codes from the DW_IC_TX_ABRT_SOURCE register
  *
- * only expected abort codes are listed here
- * refer to the datasheet for the full list
+ * Only expected abort codes are listed here,
+ * refer to the datasheet for the full list.
  */
 #define ABRT_7B_ADDR_NOACK	0
 #define ABRT_10ADDR1_NOACK	1
@@ -338,14 +338,14 @@ int i2c_dw_init(struct dw_i2c_dev *dev)
 
 	reg = dw_readl(dev, DW_IC_COMP_TYPE);
 	if (reg == ___constant_swab32(DW_IC_COMP_TYPE_VALUE)) {
-		/* Configure register endianess access */
+		/* Configure register endianness access */
 		dev->accessor_flags |= ACCESS_SWAP;
 	} else if (reg == (DW_IC_COMP_TYPE_VALUE & 0x0000ffff)) {
 		/* Configure register access mode 16bit */
 		dev->accessor_flags |= ACCESS_16BIT;
 	} else if (reg != DW_IC_COMP_TYPE_VALUE) {
-		dev_err(dev->dev, "Unknown Synopsys component type: "
-			"0x%08x\n", reg);
+		dev_err(dev->dev,
+			"Unknown Synopsys component type: 0x%08x\n", reg);
 		i2c_dw_release_lock(dev);
 		return -ENODEV;
 	}
@@ -355,7 +355,7 @@ int i2c_dw_init(struct dw_i2c_dev *dev)
 	/* Disable the adapter */
 	__i2c_dw_enable_and_wait(dev, false);
 
-	/* set standard and fast speed deviders for high/low periods */
+	/* Set standard and fast speed deviders for high/low periods */
 
 	sda_falling_time = dev->sda_falling_time ?: 300; /* ns */
 	scl_falling_time = dev->scl_falling_time ?: 300; /* ns */
@@ -444,7 +444,7 @@ int i2c_dw_init(struct dw_i2c_dev *dev)
 	dw_writel(dev, dev->tx_fifo_depth / 2, DW_IC_TX_TL);
 	dw_writel(dev, 0, DW_IC_RX_TL);
 
-	/* configure the i2c master */
+	/* Configure the I2C master */
 	dw_writel(dev, dev->master_cfg , DW_IC_CON);
 
 	i2c_dw_release_lock(dev);
@@ -480,7 +480,7 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev)
 	/* Disable the adapter */
 	__i2c_dw_enable_and_wait(dev, false);
 
-	/* if the slave address is ten bit address, enable 10BITADDR */
+	/* If the slave address is ten bit address, enable 10BITADDR */
 	if (dev->dynamic_tar_update_enabled) {
 		/*
 		 * If I2C_DYNAMIC_TAR_UPDATE is set, the 10-bit addressing
@@ -505,7 +505,7 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev)
 	 */
 	dw_writel(dev, msgs[dev->msg_write_idx].addr | ic_tar, DW_IC_TAR);
 
-	/* enforce disabled interrupts (due to HW issues) */
+	/* Enforce disabled interrupts (due to HW issues) */
 	i2c_dw_disable_int(dev);
 
 	/* Enable the adapter */
@@ -539,7 +539,7 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev)
 		u32 flags = msgs[dev->msg_write_idx].flags;
 
 		/*
-		 * if target address has changed, we need to
+		 * If target address has changed, we need to
 		 * reprogram the target address in the i2c
 		 * adapter when we are done with this transfer
 		 */
@@ -601,7 +601,7 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev)
 
 			if (msgs[dev->msg_write_idx].flags & I2C_M_RD) {
 
-				/* avoid rx buffer overrun */
+				/* Avoid rx buffer overrun */
 				if (dev->rx_outstanding >= dev->rx_fifo_depth)
 					break;
 
@@ -905,7 +905,7 @@ static irqreturn_t i2c_dw_isr(int this_irq, void *dev_id)
 
 		/*
 		 * Anytime TX_ABRT is set, the contents of the tx/rx
-		 * buffers are flushed.  Make sure to skip them.
+		 * buffers are flushed. Make sure to skip them.
 		 */
 		dw_writel(dev, 0, DW_IC_INTR_MASK);
 		goto tx_aborted;
@@ -927,7 +927,7 @@ static irqreturn_t i2c_dw_isr(int this_irq, void *dev_id)
 	if ((stat & (DW_IC_INTR_TX_ABRT | DW_IC_INTR_STOP_DET)) || dev->msg_err)
 		complete(&dev->cmd_complete);
 	else if (unlikely(dev->accessor_flags & ACCESS_INTR_MASK)) {
-		/* workaround to trigger pending interrupt */
+		/* Workaround to trigger pending interrupt */
 		stat = dw_readl(dev, DW_IC_INTR_MASK);
 		i2c_dw_disable_int(dev);
 		dw_writel(dev, stat, DW_IC_INTR_MASK);
diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h
index 26250b425e2f..3cb81fca7738 100644
--- a/drivers/i2c/busses/i2c-designware-core.h
+++ b/drivers/i2c/busses/i2c-designware-core.h
@@ -36,7 +36,7 @@
 #define DW_IC_CON_SPEED_FAST		0x4
 #define DW_IC_CON_SPEED_HIGH		0x6
 #define DW_IC_CON_SPEED_MASK		0x6
-#define DW_IC_CON_10BITADDR_MASTER	0x10
+#define DW_IC_CON_10BITADDR_MASTER		0x10
 #define DW_IC_CON_RESTART_EN		0x20
 #define DW_IC_CON_SLAVE_DISABLE		0x40
 
diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c
index 08153ea4d848..886e39753fc2 100644
--- a/drivers/i2c/busses/i2c-designware-platdrv.c
+++ b/drivers/i2c/busses/i2c-designware-platdrv.c
@@ -21,26 +21,27 @@
  * ----------------------------------------------------------------------------
  *
  */
-#include <linux/kernel.h>
-#include <linux/module.h>
+#include <linux/acpi.h>
+#include <linux/clk-provider.h>
+#include <linux/clk.h>
 #include <linux/delay.h>
 #include <linux/dmi.h>
-#include <linux/i2c.h>
-#include <linux/clk.h>
-#include <linux/clk-provider.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
 #include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/i2c.h>
 #include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/of.h>
+#include <linux/platform_data/i2c-designware.h>
 #include <linux/platform_device.h>
 #include <linux/pm.h>
 #include <linux/pm_runtime.h>
 #include <linux/property.h>
-#include <linux/io.h>
+#include <linux/sched.h>
 #include <linux/slab.h>
-#include <linux/acpi.h>
-#include <linux/platform_data/i2c-designware.h>
+
 #include "i2c-designware-core.h"
 
 static u32 i2c_dw_get_clk_rate_khz(struct dw_i2c_dev *dev)
@@ -153,11 +154,11 @@ static int i2c_dw_plat_prepare_clk(struct dw_i2c_dev *i_dev, bool prepare)
 static int dw_i2c_plat_probe(struct platform_device *pdev)
 {
 	struct dw_i2c_platform_data *pdata = dev_get_platdata(&pdev->dev);
-	struct dw_i2c_dev *dev;
 	struct i2c_adapter *adap;
+	struct dw_i2c_dev *dev;
+	u32 acpi_speed, ht = 0;
 	struct resource *mem;
 	int irq, r;
-	u32 acpi_speed, ht = 0;
 
 	irq = platform_get_irq(pdev, 0);
 	if (irq < 0)
@@ -354,7 +355,7 @@ static const struct dev_pm_ops dw_i2c_dev_pm_ops = {
 #define DW_I2C_DEV_PMOPS NULL
 #endif
 
-/* work with hotplug and coldplug */
+/* Work with hotplug and coldplug */
 MODULE_ALIAS("platform:i2c_designware");
 
 static struct platform_driver dw_i2c_driver = {
-- 
2.11.0

^ permalink raw reply related

* Re: [PATCH v2] i2c: designware: Cleaning and comment style fixes.
From: Andy Shevchenko @ 2016-12-15 14:56 UTC (permalink / raw)
  To: Luis Oliveira, wsa, robh+dt, mark.rutland, jarkko.nikula,
	mika.westerberg, linux-i2c, devicetree, linux-kernel
  Cc: Ramiro.Oliveira, Joao.Pinto, CARLOS.PALMINHA
In-Reply-To: <d7b5a22ce09539c2af343c21ca69675bef6a0a10.1481812563.git.lolivei@synopsys.com>

On Thu, 2016-12-15 at 14:38 +0000, Luis Oliveira wrote:
> The purpose of this commit is to fix some comments and styling issues
> in the
> existing code due to the need of reuse this code. What is being made
> here is:
> 
> - Sorted the headers files
> - Corrected some comments style
> - Reverse tree in the variables declaration
> - Add/remove empty lines and tabs where needed
> - Fix of a misspelled word
> 

So, I'm okay with the change as long as no-one objecting it. As I
mentioned earlier it might rise concerns and better if you put the
answers to the commit message.

Also, comment below.

> @@ -113,10 +113,10 @@
>  #define TIMEOUT			20 /* ms */
>  
>  /*
> - * hardware abort codes from the DW_IC_TX_ABRT_SOURCE register
> + * Hardware abort codes from the DW_IC_TX_ABRT_SOURCE register
>   *

> - * only expected abort codes are listed here
> - * refer to the datasheet for the full list
> + * Only expected abort codes are listed here
> + * refer to the datasheet for the full list.

Feels either comma is missing, or they are two different sentences.

>   */
>  #define ABRT_7B_ADDR_NOACK	0
>  #define ABRT_10ADDR1_NOACK	1

-- 
Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Intel Finland Oy

^ permalink raw reply

* [PATCH v2] i2c: designware: Cleaning and comment style fixes.
From: Luis Oliveira @ 2016-12-15 14:38 UTC (permalink / raw)
  To: wsa, robh+dt, mark.rutland, jarkko.nikula, andriy.shevchenko,
	mika.westerberg, linux-i2c, devicetree, linux-kernel
  Cc: Luis.Oliveira, Ramiro.Oliveira, Joao.Pinto, CARLOS.PALMINHA

The purpose of this commit is to fix some comments and styling issues in the
existing code due to the need of reuse this code. What is being made here is:

- Sorted the headers files
- Corrected some comments style
- Reverse tree in the variables declaration
- Add/remove empty lines and tabs where needed
- Fix of a misspelled word

Signed-off-by: Luis Oliveira <lolivei@synopsys.com>
---
Changes V1->V2: (Andy Shevchenko)
- Removed all the unneeded dots as suggested
- I checked and "acknowledgement" and "acknowledgment"" are both correct

 drivers/i2c/busses/i2c-designware-core.c    | 36 ++++++++++++++---------------
 drivers/i2c/busses/i2c-designware-core.h    |  2 +-
 drivers/i2c/busses/i2c-designware-platdrv.c | 27 +++++++++++-----------
 3 files changed, 33 insertions(+), 32 deletions(-)

diff --git a/drivers/i2c/busses/i2c-designware-core.c b/drivers/i2c/busses/i2c-designware-core.c
index 6d81c56184d3..254d82bb6bc3 100644
--- a/drivers/i2c/busses/i2c-designware-core.c
+++ b/drivers/i2c/busses/i2c-designware-core.c
@@ -21,17 +21,17 @@
  * ----------------------------------------------------------------------------
  *
  */
+#include <linux/delay.h>
 #include <linux/export.h>
 #include <linux/errno.h>
 #include <linux/err.h>
 #include <linux/i2c.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
-#include <linux/pm_runtime.h>
-#include <linux/delay.h>
 #include <linux/module.h>
-#include "i2c-designware-core.h"
+#include <linux/pm_runtime.h>
 
+#include "i2c-designware-core.h"
 /*
  * Registers offset
  */
@@ -98,7 +98,7 @@
 
 #define DW_IC_ERR_TX_ABRT	0x1
 
-#define DW_IC_TAR_10BITADDR_MASTER BIT(12)
+#define DW_IC_TAR_10BITADDR_MASTER		BIT(12)
 
 #define DW_IC_COMP_PARAM_1_SPEED_MODE_HIGH	(BIT(2) | BIT(3))
 #define DW_IC_COMP_PARAM_1_SPEED_MODE_MASK	GENMASK(3, 2)
@@ -113,10 +113,10 @@
 #define TIMEOUT			20 /* ms */
 
 /*
- * hardware abort codes from the DW_IC_TX_ABRT_SOURCE register
+ * Hardware abort codes from the DW_IC_TX_ABRT_SOURCE register
  *
- * only expected abort codes are listed here
- * refer to the datasheet for the full list
+ * Only expected abort codes are listed here
+ * refer to the datasheet for the full list.
  */
 #define ABRT_7B_ADDR_NOACK	0
 #define ABRT_10ADDR1_NOACK	1
@@ -338,14 +338,14 @@ int i2c_dw_init(struct dw_i2c_dev *dev)
 
 	reg = dw_readl(dev, DW_IC_COMP_TYPE);
 	if (reg == ___constant_swab32(DW_IC_COMP_TYPE_VALUE)) {
-		/* Configure register endianess access */
+		/* Configure register endianness access */
 		dev->accessor_flags |= ACCESS_SWAP;
 	} else if (reg == (DW_IC_COMP_TYPE_VALUE & 0x0000ffff)) {
 		/* Configure register access mode 16bit */
 		dev->accessor_flags |= ACCESS_16BIT;
 	} else if (reg != DW_IC_COMP_TYPE_VALUE) {
-		dev_err(dev->dev, "Unknown Synopsys component type: "
-			"0x%08x\n", reg);
+		dev_err(dev->dev,
+			"Unknown Synopsys component type: 0x%08x\n", reg);
 		i2c_dw_release_lock(dev);
 		return -ENODEV;
 	}
@@ -355,7 +355,7 @@ int i2c_dw_init(struct dw_i2c_dev *dev)
 	/* Disable the adapter */
 	__i2c_dw_enable_and_wait(dev, false);
 
-	/* set standard and fast speed deviders for high/low periods */
+	/* Set standard and fast speed deviders for high/low periods */
 
 	sda_falling_time = dev->sda_falling_time ?: 300; /* ns */
 	scl_falling_time = dev->scl_falling_time ?: 300; /* ns */
@@ -444,7 +444,7 @@ int i2c_dw_init(struct dw_i2c_dev *dev)
 	dw_writel(dev, dev->tx_fifo_depth / 2, DW_IC_TX_TL);
 	dw_writel(dev, 0, DW_IC_RX_TL);
 
-	/* configure the i2c master */
+	/* Configure the I2C master */
 	dw_writel(dev, dev->master_cfg , DW_IC_CON);
 
 	i2c_dw_release_lock(dev);
@@ -480,7 +480,7 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev)
 	/* Disable the adapter */
 	__i2c_dw_enable_and_wait(dev, false);
 
-	/* if the slave address is ten bit address, enable 10BITADDR */
+	/* If the slave address is ten bit address, enable 10BITADDR */
 	if (dev->dynamic_tar_update_enabled) {
 		/*
 		 * If I2C_DYNAMIC_TAR_UPDATE is set, the 10-bit addressing
@@ -505,7 +505,7 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev)
 	 */
 	dw_writel(dev, msgs[dev->msg_write_idx].addr | ic_tar, DW_IC_TAR);
 
-	/* enforce disabled interrupts (due to HW issues) */
+	/* Enforce disabled interrupts (due to HW issues) */
 	i2c_dw_disable_int(dev);
 
 	/* Enable the adapter */
@@ -539,7 +539,7 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev)
 		u32 flags = msgs[dev->msg_write_idx].flags;
 
 		/*
-		 * if target address has changed, we need to
+		 * If target address has changed, we need to
 		 * reprogram the target address in the i2c
 		 * adapter when we are done with this transfer
 		 */
@@ -601,7 +601,7 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev)
 
 			if (msgs[dev->msg_write_idx].flags & I2C_M_RD) {
 
-				/* avoid rx buffer overrun */
+				/* Avoid rx buffer overrun */
 				if (dev->rx_outstanding >= dev->rx_fifo_depth)
 					break;
 
@@ -905,7 +905,7 @@ static irqreturn_t i2c_dw_isr(int this_irq, void *dev_id)
 
 		/*
 		 * Anytime TX_ABRT is set, the contents of the tx/rx
-		 * buffers are flushed.  Make sure to skip them.
+		 * buffers are flushed. Make sure to skip them.
 		 */
 		dw_writel(dev, 0, DW_IC_INTR_MASK);
 		goto tx_aborted;
@@ -927,7 +927,7 @@ static irqreturn_t i2c_dw_isr(int this_irq, void *dev_id)
 	if ((stat & (DW_IC_INTR_TX_ABRT | DW_IC_INTR_STOP_DET)) || dev->msg_err)
 		complete(&dev->cmd_complete);
 	else if (unlikely(dev->accessor_flags & ACCESS_INTR_MASK)) {
-		/* workaround to trigger pending interrupt */
+		/* Workaround to trigger pending interrupt */
 		stat = dw_readl(dev, DW_IC_INTR_MASK);
 		i2c_dw_disable_int(dev);
 		dw_writel(dev, stat, DW_IC_INTR_MASK);
diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h
index 26250b425e2f..3cb81fca7738 100644
--- a/drivers/i2c/busses/i2c-designware-core.h
+++ b/drivers/i2c/busses/i2c-designware-core.h
@@ -36,7 +36,7 @@
 #define DW_IC_CON_SPEED_FAST		0x4
 #define DW_IC_CON_SPEED_HIGH		0x6
 #define DW_IC_CON_SPEED_MASK		0x6
-#define DW_IC_CON_10BITADDR_MASTER	0x10
+#define DW_IC_CON_10BITADDR_MASTER		0x10
 #define DW_IC_CON_RESTART_EN		0x20
 #define DW_IC_CON_SLAVE_DISABLE		0x40
 
diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c
index 08153ea4d848..886e39753fc2 100644
--- a/drivers/i2c/busses/i2c-designware-platdrv.c
+++ b/drivers/i2c/busses/i2c-designware-platdrv.c
@@ -21,26 +21,27 @@
  * ----------------------------------------------------------------------------
  *
  */
-#include <linux/kernel.h>
-#include <linux/module.h>
+#include <linux/acpi.h>
+#include <linux/clk-provider.h>
+#include <linux/clk.h>
 #include <linux/delay.h>
 #include <linux/dmi.h>
-#include <linux/i2c.h>
-#include <linux/clk.h>
-#include <linux/clk-provider.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
 #include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/i2c.h>
 #include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/of.h>
+#include <linux/platform_data/i2c-designware.h>
 #include <linux/platform_device.h>
 #include <linux/pm.h>
 #include <linux/pm_runtime.h>
 #include <linux/property.h>
-#include <linux/io.h>
+#include <linux/sched.h>
 #include <linux/slab.h>
-#include <linux/acpi.h>
-#include <linux/platform_data/i2c-designware.h>
+
 #include "i2c-designware-core.h"
 
 static u32 i2c_dw_get_clk_rate_khz(struct dw_i2c_dev *dev)
@@ -153,11 +154,11 @@ static int i2c_dw_plat_prepare_clk(struct dw_i2c_dev *i_dev, bool prepare)
 static int dw_i2c_plat_probe(struct platform_device *pdev)
 {
 	struct dw_i2c_platform_data *pdata = dev_get_platdata(&pdev->dev);
-	struct dw_i2c_dev *dev;
 	struct i2c_adapter *adap;
+	struct dw_i2c_dev *dev;
+	u32 acpi_speed, ht = 0;
 	struct resource *mem;
 	int irq, r;
-	u32 acpi_speed, ht = 0;
 
 	irq = platform_get_irq(pdev, 0);
 	if (irq < 0)
@@ -354,7 +355,7 @@ static const struct dev_pm_ops dw_i2c_dev_pm_ops = {
 #define DW_I2C_DEV_PMOPS NULL
 #endif
 
-/* work with hotplug and coldplug */
+/* Work with hotplug and coldplug */
 MODULE_ALIAS("platform:i2c_designware");
 
 static struct platform_driver dw_i2c_driver = {
-- 
2.11.0

^ permalink raw reply related

* Re: [PATCH v2] i2c: designware: add reset interface
From: Phil Reid @ 2016-12-15 14:11 UTC (permalink / raw)
  To: Andy Shevchenko, Zhangfei Gao, Wolfram Sang, mika.westerberg,
	jarkko.nikula
  Cc: linux-i2c, linux-arm-kernel
In-Reply-To: <1481805227.9552.15.camel@linux.intel.com>

On 15/12/2016 20:33, Andy Shevchenko wrote:
> On Thu, 2016-12-15 at 16:59 +0800, Zhangfei Gao wrote:
>> Some platforms like hi3660 need do reset first to allow accessing
>> registers
>
> Patch itself looks good, but would be nice to have it tested.
>
> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
>
>>
>> Signed-off-by: Zhangfei Gao <zhangfei.gao@linaro.org>
>> ---
>>  drivers/i2c/busses/i2c-designware-core.h    |  1 +
>>  drivers/i2c/busses/i2c-designware-platdrv.c | 28
>> ++++++++++++++++++++++++----
>>  2 files changed, 25 insertions(+), 4 deletions(-)
>>
>> diff --git a/drivers/i2c/busses/i2c-designware-core.h
>> b/drivers/i2c/busses/i2c-designware-core.h
>> index 0d44d2a..94b14fa 100644
>> --- a/drivers/i2c/busses/i2c-designware-core.h
>> +++ b/drivers/i2c/busses/i2c-designware-core.h
>> @@ -80,6 +80,7 @@ struct dw_i2c_dev {
>>  	void __iomem		*base;
>>  	struct completion	cmd_complete;
>>  	struct clk		*clk;
>> +	struct reset_control	*rst;
>>  	u32			(*get_clk_rate_khz) (struct
>> dw_i2c_dev *dev);
>>  	struct dw_pci_controller *controller;
>>  	int			cmd_err;
>> diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c
>> b/drivers/i2c/busses/i2c-designware-platdrv.c
>> index 0b42a12..e9016ae 100644
>> --- a/drivers/i2c/busses/i2c-designware-platdrv.c
>> +++ b/drivers/i2c/busses/i2c-designware-platdrv.c
>> @@ -38,6 +38,7 @@
>>  #include <linux/pm_runtime.h>
>>  #include <linux/property.h>
>>  #include <linux/io.h>
>> +#include <linux/reset.h>
>>  #include <linux/slab.h>
>>  #include <linux/acpi.h>
>>  #include <linux/platform_data/i2c-designware.h>
>> @@ -176,6 +177,14 @@ static int dw_i2c_plat_probe(struct
>> platform_device *pdev)
>>  	dev->irq = irq;
>>  	platform_set_drvdata(pdev, dev);
>>
>> +	dev->rst = devm_reset_control_get_optional(&pdev->dev, NULL);
>> +	if (IS_ERR(dev->rst)) {
>> +		if (PTR_ERR(dev->rst) == -EPROBE_DEFER)
>> +			return -EPROBE_DEFER;
>> +	} else {
>> +		reset_control_deassert(dev->rst);
>> +	}
>> +
More for my education. But some drivers seem to handle the error codes a little more explicitly.
Whats the best approach?

eg: From usb/dwc2 driver it continues only if ENOENT / ENOTSUPP errors are return
and ENOMEM / EINVAL etc is a fatal error.

hsotg->reset = devm_reset_control_get_optional(hsotg->dev, "dwc2");
if (IS_ERR(hsotg->reset)) {
         ret = PTR_ERR(hsotg->reset);
         switch (ret) {
         case -ENOENT:
         case -ENOTSUPP:
                 hsotg->reset = NULL;
                 break;
         default:
                 dev_err(hsotg->dev, "error getting reset control %d\n",
                         ret);
                 return ret;
         }
}

if (hsotg->reset)
         reset_control_deassert(hsotg->reset);

Regards
Phil

^ permalink raw reply

* Re: [PATCH v2] i2c: designware: add reset interface
From: Andy Shevchenko @ 2016-12-15 12:33 UTC (permalink / raw)
  To: Zhangfei Gao, Wolfram Sang, mika.westerberg, jarkko.nikula
  Cc: linux-arm-kernel, linux-i2c
In-Reply-To: <1481792388-13781-1-git-send-email-zhangfei.gao@linaro.org>

On Thu, 2016-12-15 at 16:59 +0800, Zhangfei Gao wrote:
> Some platforms like hi3660 need do reset first to allow accessing
> registers

Patch itself looks good, but would be nice to have it tested.

Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>

> 
> Signed-off-by: Zhangfei Gao <zhangfei.gao@linaro.org>
> ---
>  drivers/i2c/busses/i2c-designware-core.h    |  1 +
>  drivers/i2c/busses/i2c-designware-platdrv.c | 28
> ++++++++++++++++++++++++----
>  2 files changed, 25 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/i2c/busses/i2c-designware-core.h
> b/drivers/i2c/busses/i2c-designware-core.h
> index 0d44d2a..94b14fa 100644
> --- a/drivers/i2c/busses/i2c-designware-core.h
> +++ b/drivers/i2c/busses/i2c-designware-core.h
> @@ -80,6 +80,7 @@ struct dw_i2c_dev {
>  	void __iomem		*base;
>  	struct completion	cmd_complete;
>  	struct clk		*clk;
> +	struct reset_control	*rst;
>  	u32			(*get_clk_rate_khz) (struct
> dw_i2c_dev *dev);
>  	struct dw_pci_controller *controller;
>  	int			cmd_err;
> diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c
> b/drivers/i2c/busses/i2c-designware-platdrv.c
> index 0b42a12..e9016ae 100644
> --- a/drivers/i2c/busses/i2c-designware-platdrv.c
> +++ b/drivers/i2c/busses/i2c-designware-platdrv.c
> @@ -38,6 +38,7 @@
>  #include <linux/pm_runtime.h>
>  #include <linux/property.h>
>  #include <linux/io.h>
> +#include <linux/reset.h>
>  #include <linux/slab.h>
>  #include <linux/acpi.h>
>  #include <linux/platform_data/i2c-designware.h>
> @@ -176,6 +177,14 @@ static int dw_i2c_plat_probe(struct
> platform_device *pdev)
>  	dev->irq = irq;
>  	platform_set_drvdata(pdev, dev);
>  
> +	dev->rst = devm_reset_control_get_optional(&pdev->dev, NULL);
> +	if (IS_ERR(dev->rst)) {
> +		if (PTR_ERR(dev->rst) == -EPROBE_DEFER)
> +			return -EPROBE_DEFER;
> +	} else {
> +		reset_control_deassert(dev->rst);
> +	}
> +
>  	/* fast mode by default because of legacy reasons */
>  	dev->clk_freq = 400000;
>  
> @@ -207,12 +216,13 @@ static int dw_i2c_plat_probe(struct
> platform_device *pdev)
>  	    && dev->clk_freq != 1000000 && dev->clk_freq != 3400000)
> {
>  		dev_err(&pdev->dev,
>  			"Only 100kHz, 400kHz, 1MHz and 3.4MHz
> supported");
> -		return -EINVAL;
> +		r = -EINVAL;
> +		goto exit_reset;
>  	}
>  
>  	r = i2c_dw_eval_lock_support(dev);
>  	if (r)
> -		return r;
> +		goto exit_reset;
>  
>  	dev->functionality =
>  		I2C_FUNC_I2C |
> @@ -270,10 +280,18 @@ static int dw_i2c_plat_probe(struct
> platform_device *pdev)
>  	}
>  
>  	r = i2c_dw_probe(dev);
> -	if (r && !dev->pm_runtime_disabled)
> -		pm_runtime_disable(&pdev->dev);
> +	if (r)
> +		goto exit_probe;
>  
>  	return r;
> +
> +exit_probe:
> +	if (!dev->pm_runtime_disabled)
> +		pm_runtime_disable(&pdev->dev);
> +exit_reset:
> +	if (!IS_ERR_OR_NULL(dev->rst))
> +		reset_control_assert(dev->rst);
> +	return r;
>  }
>  
>  static int dw_i2c_plat_remove(struct platform_device *pdev)
> @@ -290,6 +308,8 @@ static int dw_i2c_plat_remove(struct
> platform_device *pdev)
>  	pm_runtime_put_sync(&pdev->dev);
>  	if (!dev->pm_runtime_disabled)
>  		pm_runtime_disable(&pdev->dev);
> +	if (!IS_ERR_OR_NULL(dev->rst))
> +		reset_control_assert(dev->rst);
>  
>  	return 0;
>  }

-- 
Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Intel Finland Oy

^ permalink raw reply

* [PATCH v2] i2c: designware: add reset interface
From: Zhangfei Gao @ 2016-12-15  8:59 UTC (permalink / raw)
  To: Wolfram Sang, andriy.shevchenko, mika.westerberg, jarkko.nikula
  Cc: linux-arm-kernel, linux-i2c, Zhangfei Gao
In-Reply-To: <1479789700-19532-1-git-send-email-zhangfei.gao@linaro.org>

Some platforms like hi3660 need do reset first to allow accessing registers

Signed-off-by: Zhangfei Gao <zhangfei.gao@linaro.org>
---
 drivers/i2c/busses/i2c-designware-core.h    |  1 +
 drivers/i2c/busses/i2c-designware-platdrv.c | 28 ++++++++++++++++++++++++----
 2 files changed, 25 insertions(+), 4 deletions(-)

diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h
index 0d44d2a..94b14fa 100644
--- a/drivers/i2c/busses/i2c-designware-core.h
+++ b/drivers/i2c/busses/i2c-designware-core.h
@@ -80,6 +80,7 @@ struct dw_i2c_dev {
 	void __iomem		*base;
 	struct completion	cmd_complete;
 	struct clk		*clk;
+	struct reset_control	*rst;
 	u32			(*get_clk_rate_khz) (struct dw_i2c_dev *dev);
 	struct dw_pci_controller *controller;
 	int			cmd_err;
diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c
index 0b42a12..e9016ae 100644
--- a/drivers/i2c/busses/i2c-designware-platdrv.c
+++ b/drivers/i2c/busses/i2c-designware-platdrv.c
@@ -38,6 +38,7 @@
 #include <linux/pm_runtime.h>
 #include <linux/property.h>
 #include <linux/io.h>
+#include <linux/reset.h>
 #include <linux/slab.h>
 #include <linux/acpi.h>
 #include <linux/platform_data/i2c-designware.h>
@@ -176,6 +177,14 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
 	dev->irq = irq;
 	platform_set_drvdata(pdev, dev);
 
+	dev->rst = devm_reset_control_get_optional(&pdev->dev, NULL);
+	if (IS_ERR(dev->rst)) {
+		if (PTR_ERR(dev->rst) == -EPROBE_DEFER)
+			return -EPROBE_DEFER;
+	} else {
+		reset_control_deassert(dev->rst);
+	}
+
 	/* fast mode by default because of legacy reasons */
 	dev->clk_freq = 400000;
 
@@ -207,12 +216,13 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
 	    && dev->clk_freq != 1000000 && dev->clk_freq != 3400000) {
 		dev_err(&pdev->dev,
 			"Only 100kHz, 400kHz, 1MHz and 3.4MHz supported");
-		return -EINVAL;
+		r = -EINVAL;
+		goto exit_reset;
 	}
 
 	r = i2c_dw_eval_lock_support(dev);
 	if (r)
-		return r;
+		goto exit_reset;
 
 	dev->functionality =
 		I2C_FUNC_I2C |
@@ -270,10 +280,18 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
 	}
 
 	r = i2c_dw_probe(dev);
-	if (r && !dev->pm_runtime_disabled)
-		pm_runtime_disable(&pdev->dev);
+	if (r)
+		goto exit_probe;
 
 	return r;
+
+exit_probe:
+	if (!dev->pm_runtime_disabled)
+		pm_runtime_disable(&pdev->dev);
+exit_reset:
+	if (!IS_ERR_OR_NULL(dev->rst))
+		reset_control_assert(dev->rst);
+	return r;
 }
 
 static int dw_i2c_plat_remove(struct platform_device *pdev)
@@ -290,6 +308,8 @@ static int dw_i2c_plat_remove(struct platform_device *pdev)
 	pm_runtime_put_sync(&pdev->dev);
 	if (!dev->pm_runtime_disabled)
 		pm_runtime_disable(&pdev->dev);
+	if (!IS_ERR_OR_NULL(dev->rst))
+		reset_control_assert(dev->rst);
 
 	return 0;
 }
-- 
2.7.4

^ permalink raw reply related

* Re: [PATCH] i2c: designware: add reset interface
From: zhangfei @ 2016-12-15  8:56 UTC (permalink / raw)
  To: Andy Shevchenko, Wolfram Sang
  Cc: linux-arm-kernel, linux-i2c, Jarkko Nikula, Mika Westerberg
In-Reply-To: <1481742050.9552.5.camel@linux.intel.com>



On 2016年12月15日 03:00, Andy Shevchenko wrote:
> On Tue, 2016-12-13 at 21:34 +0100, Wolfram Sang wrote:
>> On Tue, Nov 22, 2016 at 12:41:40PM +0800, Zhangfei Gao wrote:
>>> Some platforms like hi3660 need do reset first to allow accessing
>>> registers
>>>
>>> Signed-off-by: Zhangfei Gao <zhangfei.gao@linaro.org>
>> Adding designware maintainers to CC...
>>
>>> ---
>>>   drivers/i2c/busses/i2c-designware-core.h    | 1 +
>>>   drivers/i2c/busses/i2c-designware-platdrv.c | 5 +++++
>>>   2 files changed, 6 insertions(+)
>>>
>>> diff --git a/drivers/i2c/busses/i2c-designware-core.h
>>> b/drivers/i2c/busses/i2c-designware-core.h
>>> index 0d44d2a..94b14fa 100644
>>> --- a/drivers/i2c/busses/i2c-designware-core.h
>>> +++ b/drivers/i2c/busses/i2c-designware-core.h
>>> @@ -80,6 +80,7 @@ struct dw_i2c_dev {
>>>   	void __iomem		*base;
>>>   	struct completion	cmd_complete;
>>>   	struct clk		*clk;
>>> +	struct reset_control	*rst;
>>>   	u32			(*get_clk_rate_khz) (struct
>>> dw_i2c_dev *dev);
>>>   	struct dw_pci_controller *controller;
>>>   	int			cmd_err;
>>> diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c
>>> b/drivers/i2c/busses/i2c-designware-platdrv.c
>>> index 0b42a12..fd80e58 100644
>>> --- a/drivers/i2c/busses/i2c-designware-platdrv.c
>>> +++ b/drivers/i2c/busses/i2c-designware-platdrv.c
>>> @@ -38,6 +38,7 @@
>>>   #include <linux/pm_runtime.h>
>>>   #include <linux/property.h>
>>>   #include <linux/io.h>
>>> +#include <linux/reset.h>
>>>   #include <linux/slab.h>
>>>   #include <linux/acpi.h>
>>>   #include <linux/platform_data/i2c-designware.h>
>>> @@ -176,6 +177,10 @@ static int dw_i2c_plat_probe(struct
>>> platform_device *pdev)
>>>   	dev->irq = irq;
>>>   	platform_set_drvdata(pdev, dev);
>>>   
>>> +	dev->rst = devm_reset_control_get(&pdev->dev, NULL);
>>> +	if (!IS_ERR(dev->rst))
>>> +		reset_control_reset(dev->rst);
> Do we care about EPROBE_DEFER?
>
> Perhaps on error path we need to assert it.
>
> And I guess it should be devm_reset_control_get_optional().

Thanks Andy
Good suggestion, will update accordingly.

Thanks

^ permalink raw reply

* Re: [[RFC V3] 1/1] i2c: imx: add slave support
From: Frkuska, Joshua @ 2016-12-15  5:53 UTC (permalink / raw)
  To: vladimir_zapolskiy, linux-i2c; +Cc: wsa, syrchin, peda, Wang, Jiada (ESD)
In-Reply-To: <b125df4d-cde7-967d-13eb-9047285fe6ea@mentor.com>


Hello Vladimir,

(sorry for previously sending an html version)

Thank you very much for the review. Please find my comments inline

On 12/14/2016 10:30 PM, Vladimir Zapolskiy wrote:
> Hi Joshua,
>
> please find review comments below, mainly stylistic ones.
>
> On 12/14/2016 08:01 AM, Joshua Frkuska wrote:
>> Add I2C slave provider using the generic slave interface.
>> It also supports master transactions when the slave in the idle mode.
>>
>> Signed-off-by: Maxim Syrchin <msyrchin@dev.rtsoft.ru>
>> Signed-off-by: Joshua Frkuska <joshua_frkuska@mentor.com>
>
> should you preserve Maxim's authorship?
The design for the most part is his. I am preserving it for this reason.
>
>> ---
>>  drivers/i2c/busses/i2c-imx.c | 724
>> +++++++++++++++++++++++++++++++++++++++++--
>>  1 file changed, 694 insertions(+), 30 deletions(-)
>>
>> diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c
>> index 47fc1f1..7b2aeb8 100644
>> --- a/drivers/i2c/busses/i2c-imx.c
>> +++ b/drivers/i2c/busses/i2c-imx.c
>> @@ -53,6 +53,7 @@
>>  #include <linux/pm_runtime.h>
>>  #include <linux/sched.h>
>>  #include <linux/slab.h>
>> +#include <linux/kthread.h>
>
> Please insert #include keeping the list alphabetically numbered.
agreed
>
>>
>>  /* This will be the driver name the kernel reports */
>>  #define DRIVER_NAME "imx-i2c"
>> @@ -60,6 +61,13 @@
>>  /* Default value */
>>  #define IMX_I2C_BIT_RATE    100000    /* 100kHz */
>>
>> +/* Wait delays */
>> +#define STATE_MIN_WAIT_TIME    1 /* 1 jiffy */
>> +#define STATE_WAIT_TIME    (HZ / 10)
>> +
>> +#define MAX_EVENTS (1<<4)
>
> checkpatch warnings:
please let me know the checkpatch level you are checking on
>
> CHECK: spaces preferred around that '<<' (ctx:VxV)
> #35: FILE: drivers/i2c/busses/i2c-imx.c:68:
> +#define MAX_EVENTS (1<<4)
>                       ^
agreed
>
> CHECK: Prefer using the BIT macro
> #35: FILE: drivers/i2c/busses/i2c-imx.c:68:
> +#define MAX_EVENTS (1<<4)
>
> The second warning seems to be irrelevant, please fix the first one.
agreed
>
>> +#define EUNDEFINED 4000
>
> I would recommend to avoid introduction of new errnos, please use
> one of the existing.
agreed
>
>> +
>>  /*
>>   * Enable DMA if transfer byte size is bigger than this threshold.
>>   * As the hardware request, it must bigger than 4 bytes.\
>> @@ -171,6 +179,30 @@ enum imx_i2c_type {
>>      VF610_I2C,
>>  };
>>
>> +enum i2c_imx_state {
>> +    STATE_IDLE = 0,
>> +    STATE_SLAVE,
>> +    STATE_MASTER,
>> +    STATE_SP
>> +};
>> +
>> +enum i2c_imx_events {
>> +    EVT_AL = 0,
>> +    EVT_SI,
>> +    EVT_START,
>> +    EVT_STOP,
>> +    EVT_POLL,
>> +    EVT_INVALID,
>> +    EVT_ENTRY
>> +};
>> +
>> +struct evt_queue {
>> +    atomic_t count;
>> +    atomic_t ir;
>> +    atomic_t iw;
>> +    unsigned int evt[MAX_EVENTS];
>> +};
>> +
>>  struct imx_i2c_hwdata {
>>      enum imx_i2c_type    devtype;
>>      unsigned        regshift;
>> @@ -193,6 +225,7 @@ struct imx_i2c_dma {
>>
>>  struct imx_i2c_struct {
>>      struct i2c_adapter    adapter;
>> +    struct i2c_client    *slave;
>>      struct clk        *clk;
>>      void __iomem        *base;
>>      wait_queue_head_t    queue;
>> @@ -210,6 +243,18 @@ struct imx_i2c_struct {
>>      struct pinctrl_state *pinctrl_pins_gpio;
>>
>>      struct imx_i2c_dma    *dma;
>> +
>> +    unsigned int        state;
>> +    struct evt_queue    events;
>> +    atomic_t        last_error;
>
> Please replace 'last_error' type to 'int', this will require changes
> in the code as well.
>
do you suggest here that the address will always be aligned and thus not 
need atomic_t type?
> In general the usage of this variable is questionable, while
> it can be set to 0, -EBUSY, -ETIMEDOUT, -EAGAIN and -EUNDEFINED,
> from the code there are only two classes impact runtime behaviour:
> -EUNDEFINED and anything else, I didn't notice the difference between
> e.g. 0 and -EBUSY.
>
agreed, it might be removable or turned into a simple flag
>> +
>> +    int            master_interrupt;
>> +    int            start_retry_cnt;
>> +    int            slave_poll_cnt;
>> +
>> +    struct task_struct    *slave_task;
>> +    wait_queue_head_t    state_queue;
>> +
>
> Please drop the empty line above.
agreed
>
>>  };
>>
>>  static const struct imx_i2c_hwdata imx1_i2c_hwdata = {
>> @@ -414,17 +459,29 @@ static void i2c_imx_dma_free(struct
>> imx_i2c_struct *i2c_imx)
>>  static int i2c_imx_bus_busy(struct imx_i2c_struct *i2c_imx, int
>> for_busy)
>>  {
>>      unsigned long orig_jiffies = jiffies;
>> -    unsigned int temp;
>> +    unsigned int temp, ctl;
>> +
>>
>>      dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__);
>>
>>      while (1) {
>>          temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR);
>> +        ctl = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
>> +
>> +        /*
>> +         *    Check for arbitration lost. Datasheet recommends to
>> +         *    clean IAL bit in interrupt handler before any other
>> +         *    action.
>> +         *
>> +         *    We can detect if controller resets MSTA bit, because
>> +         *    hardware is switched to slave mode if arbitration was
>> +         *    lost.
>> +         */
>>
>> -        /* check for arbitration lost */
>> -        if (temp & I2SR_IAL) {
>> -            temp &= ~I2SR_IAL;
>> -            imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2SR);
>> +        if (for_busy && !(ctl & I2CR_MSTA)) {
>> +            dev_dbg(&i2c_imx->adapter.dev,
>> +                "<%s> Lost arbitration (SR = %02x, CR = %02x)\n",
>> +                __func__, temp, ctl);
>>              return -EAGAIN;
>>          }
>>
>> @@ -443,16 +500,501 @@ static int i2c_imx_bus_busy(struct
>> imx_i2c_struct *i2c_imx, int for_busy)
>>      return 0;
>>  }
>>
>> +#ifdef CONFIG_I2C_SLAVE
>> +
>> +static void i2c_imx_enable_i2c_controller(struct imx_i2c_struct
>> *i2c_imx);
>> +static void set_state(struct imx_i2c_struct *i2c_imx, unsigned int
>> new);
>> +static int i2c_imx_hw_start(struct imx_i2c_struct *i2c_imx);
>> +static void i2c_imx_stop(struct imx_i2c_struct *i2c_imx);
>> +
>> +static inline int evt_find_next_idx(atomic_t *v)
>> +{
>> +    return atomic_inc_return(v) & (MAX_EVENTS - 1);
>> +}
>> +
>> +static unsigned int evt_put(struct evt_queue *stk, unsigned int evt)
>> +{
>> +    int count = atomic_inc_return(&stk->count);
>> +    int idx;
>> +
>> +    if (count < MAX_EVENTS) {
>> +        idx = evt_find_next_idx(&stk->iw);
>> +        stk->evt[idx] = evt;
>> +    } else {
>> +        atomic_dec(&stk->count);
>> +        return EVT_INVALID;
>> +    }
>> +
>> +    return 0;
>> +}
>> +
>> +static unsigned int evt_get(struct evt_queue *stk)
>> +{
>> +    int count = atomic_dec_return(&stk->count);
>> +    int idx;
>> +
>> +    if (count >= 0) {
>> +        idx = evt_find_next_idx(&stk->ir);
>> +    } else {
>> +        atomic_inc(&stk->count);
>> +        return EVT_INVALID;
>> +    }
>> +
>> +    return stk->evt[idx];
>> +}
>> +
>> +static unsigned int evt_is_empty(struct evt_queue *stk)
>
> static bool evt_is_empty()
agreed
>
>> +{
>> +    int ret = atomic_read(&stk->count);
>> +
>> +    return (ret <= 0);
>> +}
>> +
>> +static void evt_init(struct evt_queue *stk)
>> +{
>> +    atomic_set(&stk->count, 0);
>> +    atomic_set(&stk->iw, 0);
>> +    atomic_set(&stk->ir, 0);
>> +}
>> +
>> +
>
> Please don't use multiple blank lines.
agreed
>
>> +static void i2c_imx_clear_ial_bit(struct imx_i2c_struct *i2c_imx)
>> +{
>> +    unsigned int status;
>> +
>> +    status = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR);
>> +    status &= ~I2SR_IAL;
>> +    imx_i2c_write_reg(status, i2c_imx, IMX_I2C_I2SR);
>> +}
>> +
>> +static void i2c_imx_slave_init(struct imx_i2c_struct *i2c_imx)
>> +{
>> +    unsigned int temp;
>> +
>> +    dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__);
>> +
>> +    i2c_imx_enable_i2c_controller(i2c_imx);
>> +
>> +    /* Set Slave mode with interrupt enable */
>> +    temp = i2c_imx->hwdata->i2cr_ien_opcode | I2CR_IIEN;
>> +    imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
>> +}
>> +
>> +
>
> Please don't use multiple blank lines.
agreed
>
>> +static void i2c_imx_slave_process_irq(struct imx_i2c_struct *i2c_imx)
>> +{
>> +    unsigned int status, ctl;
>> +    u8 data;
>> +
>> +    status = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR);
>> +    ctl = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
>> +
>> +    if (status & I2SR_IAAS) {
>> +        if (status & I2SR_SRW) {
>> +            /* master wants to read from us */
>> +            i2c_slave_event(i2c_imx->slave,
>> +                I2C_SLAVE_READ_REQUESTED, &data);
>
> Alignment should match open parenthesis.
agreed
>
>> +            ctl |= I2CR_MTX;
>> +            imx_i2c_write_reg(ctl, i2c_imx, IMX_I2C_I2CR);
>> +
>> +            /*send data */
>> +            imx_i2c_write_reg(data, i2c_imx, IMX_I2C_I2DR);
>> +        } else {
>> +            dev_dbg(&i2c_imx->adapter.dev, "write requested");
>> +            i2c_slave_event(i2c_imx->slave,
>> +                I2C_SLAVE_WRITE_REQUESTED, &data);
>
> Alignment should match open parenthesis.
agreed
>
>> +            /*slave receive */
>> +            ctl &= ~I2CR_MTX;
>> +            imx_i2c_write_reg(ctl, i2c_imx, IMX_I2C_I2CR);
>> +
>> +            /*dummy read */
>> +            data = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR);
>
> For dummy read there is no need to assign the result to 'data'.
agreed
>
>> +        }
>> +    } else {
>> +        /* slave send */
>> +        if (ctl & I2CR_MTX) {
>> +            if (!(status & I2SR_RXAK)) {    /*ACK received */
>> +                i2c_slave_event(i2c_imx->slave,
>> +                    I2C_SLAVE_READ_PROCESSED, &data);
>
> Alignment should match open parenthesis.
agreed
>
>> +                ctl |= I2CR_MTX;
>> +                imx_i2c_write_reg(ctl, i2c_imx, IMX_I2C_I2CR);
>> +                /*send data */
>> +                imx_i2c_write_reg(data, i2c_imx, IMX_I2C_I2DR);
>> +            } else {
>> +                /*no ACK. */
>> +                /*dummy read */
>> +                dev_dbg(&i2c_imx->adapter.dev, "read requested");
>> +                i2c_slave_event(i2c_imx->slave,
>> +                    I2C_SLAVE_READ_REQUESTED, &data);
>
> Alignment should match open parenthesis.
agreed
>> +
>> +                ctl &= ~I2CR_MTX;
>> +                imx_i2c_write_reg(ctl, i2c_imx, IMX_I2C_I2CR);
>> +                imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR);
>> +            }
>> +        } else {    /*read */
>> +            ctl &= ~I2CR_MTX;
>> +            imx_i2c_write_reg(ctl, i2c_imx, IMX_I2C_I2CR);
>> +
>> +            /*read */
>> +            data = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR);
>> +            dev_dbg(&i2c_imx->adapter.dev, "received %x",
>> +                (unsigned int) data);
>
agreed
> Cast is not needed here IMHO.
>
>> + i2c_slave_event(i2c_imx->slave,
>> +                I2C_SLAVE_WRITE_RECEIVED, &data);
>
> Alignment should match open parenthesis.
agreed
>
>> +        }
>> +    }
>> +}
>> +
>> +
>
> Please don't use multiple blank lines.
agreed
>
>> +static int idle_evt_handler(struct imx_i2c_struct *i2c_imx, unsigned
>> int event)
>> +{
>> +    u8 reg;
>> +
>> +    switch (event) {
>> +    case EVT_ENTRY:
>> + imx_i2c_write_reg(i2c_imx->hwdata->i2cr_ien_opcode ^ I2CR_IEN,
>> +            i2c_imx, IMX_I2C_I2CR);
>
> Alignment should match open parenthesis.
agreed
>
>> + i2c_imx_enable_i2c_controller(i2c_imx);
>> + imx_i2c_write_reg(i2c_imx->hwdata->i2cr_ien_opcode | I2CR_IIEN,
>> +                 i2c_imx, IMX_I2C_I2CR);
>
> Alignment should match open parenthesis.
agreed
>
>> +        if (atomic_read(&i2c_imx->last_error) == -EUNDEFINED) {
>> +            dev_dbg(&i2c_imx->adapter.dev, "Reset lost START event\n");
>> +            atomic_set(&i2c_imx->last_error, -EBUSY);
>> +        }
>> +        i2c_imx->start_retry_cnt = 0;
>> +        return 0;
>> +    case EVT_AL:
>> +        i2c_imx_clear_ial_bit(i2c_imx);
>> +        break;
>> +    case EVT_SI:
>> +        set_state(i2c_imx, STATE_SLAVE);
>> +        i2c_imx_slave_process_irq(i2c_imx);
>> +        break;
>> +    case EVT_START:
>> +        reg = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR);
>> +        if ((reg & I2SR_IBB) != 0) {
>> +            atomic_set(&i2c_imx->last_error, -EBUSY);
>> +            break;
>> +        }
>> +
>> +        reg = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
>> +        reg |= I2CR_MSTA;
>> +        imx_i2c_write_reg(reg, i2c_imx, IMX_I2C_I2CR);
>> +        set_state(i2c_imx, STATE_SP);
>> +        i2c_imx->start_retry_cnt = 0;
>> +        return 0;
>> +    case EVT_STOP:
>> +    case EVT_POLL:
>> +    default:
>> +        break;
>> +    }
>> +
>> +    return STATE_WAIT_TIME;
>> +}
>> +
>> +static int master_evt_handler(struct imx_i2c_struct *i2c_imx,
>> +                  unsigned int event)
>> +{
>> +    switch (event) {
>> +    case EVT_ENTRY:
>> +        i2c_imx->start_retry_cnt = 0;
>> +        return 0;
>> +    case EVT_AL:
>> +        set_state(i2c_imx, STATE_IDLE);
>> +        break;
>> +    case EVT_SI:
>> +        break;
>> +    case EVT_START:
>> +        atomic_set(&i2c_imx->last_error, -EBUSY);
>> +        break;
>> +    case EVT_STOP:
>> + imx_i2c_write_reg(i2c_imx->hwdata->i2sr_clr_opcode, i2c_imx,
>> +                IMX_I2C_I2SR);
>
> Alignment should match open parenthesis.
agreed
>
>> + imx_i2c_write_reg(i2c_imx->hwdata->i2cr_ien_opcode | I2CR_IIEN,
>> +                i2c_imx, IMX_I2C_I2CR);
>
> Alignment should match open parenthesis.
agreed
>
>> +
>> +        i2c_imx->stopped = 1;
>> +        udelay(50);
>
> CHECK: usleep_range is preferred over udelay; see
> Documentation/timers/timers-howto.txt
> #352: FILE: drivers/i2c/busses/i2c-imx.c:717:
> +        udelay(50);
agreed
>
>
>> +        set_state(i2c_imx, STATE_IDLE);
>> +        return 0;
>> +    case EVT_POLL:
>> +    default:
>> +        break;
>> +    }
>> +
>> +    return STATE_WAIT_TIME;
>> +}
>> +
>> +static int slave_evt_handler (struct imx_i2c_struct *i2c_imx,
>
> Please drop the space         ^^^^
agreed
>
>> +                  unsigned int event)
>> +{
>> +    u8 reg, data;
>> +
>> +    switch (event) {
>> +    case EVT_ENTRY:
>> +        if (atomic_read(&i2c_imx->last_error) == -EUNDEFINED) {
>> +            dev_dbg(&i2c_imx->adapter.dev, "Reset lost START event\n");
>> +            atomic_set(&i2c_imx->last_error, -EBUSY);
>> +        }
>> +        i2c_imx->start_retry_cnt = 0;
>> +        i2c_imx->slave_poll_cnt = 0;
>> +        return 0;
>> +    case EVT_AL:
>> +        set_state(i2c_imx, STATE_IDLE);
>> +        break;
>> +    case EVT_START:
>> +        reg = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
>> +        atomic_set(&i2c_imx->last_error, -EBUSY);
>> +        break;
>> +    case EVT_STOP:
>> +        break;
>> +    case EVT_SI:
>> +        i2c_imx_slave_process_irq(i2c_imx);
>> +        reg = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR);
>> +        if ((reg & I2SR_IBB) == 0) {
>> +            data = 0;
>> +            set_state(i2c_imx,  STATE_IDLE);
>> +            dev_dbg(&i2c_imx->adapter.dev, "end of package");
>> +            i2c_slave_event(i2c_imx->slave, I2C_SLAVE_STOP, &data);
>> +        }
>> +        if (i2c_imx->slave_poll_cnt > 10) {
>> +            dev_err(&i2c_imx->adapter.dev,
>> +                "Too much slave loops (%i)\n",
>> +                i2c_imx->slave_poll_cnt);
>> +        }
>> +
>> +        i2c_imx->slave_poll_cnt = 0;
>> +        break;
>> +    case EVT_POLL:
>> +        reg = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR);
>> +        if ((reg & I2SR_IBB) == 0) {
>> +            data = 0;
>> +            set_state(i2c_imx,  STATE_IDLE);
>> +            dev_dbg(&i2c_imx->adapter.dev, "end of package");
>> +            i2c_slave_event(i2c_imx->slave, I2C_SLAVE_STOP, &data);
>> +            if (i2c_imx->slave_poll_cnt > 10) {
>> +                dev_err(&i2c_imx->adapter.dev,
>> +                    "Too much slave loops (%i)\n",
>> +                    i2c_imx->slave_poll_cnt);
>> +            }
>> +
>> +            i2c_imx->slave_poll_cnt = 0;
>> +        }
>> +
>> +        /*
>> +         * TODO: do "dummy read" if no interrupts or stop condition
>> +         * for more then 10 wait loops
>> +         */
>> +        i2c_imx->slave_poll_cnt += 1;
>> +        if (i2c_imx->slave_poll_cnt % 10 == 0)
>> +            imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR);
>> +        break;
>> +    default:
>> +        break;
>> +    }
>> +
>> +    return STATE_MIN_WAIT_TIME;
>> +}
>> +
>> +static int sp_evt_handler (struct imx_i2c_struct *i2c_imx, unsigned
>> int event)
>
> Please drop the space      ^^^^
agreed
>
>> +{
>> +    u8 reg;
>> +
>> +    switch (event) {
>> +    case EVT_AL:
>> +        dev_dbg(&i2c_imx->adapter.dev, "Lost arbitration on START");
>> +        atomic_set(&i2c_imx->last_error, -EAGAIN);
>> +        set_state(i2c_imx, STATE_IDLE);
>> +        return 0;
>> +    case EVT_SI:
>> +        set_state(i2c_imx, STATE_IDLE);
>> +        evt_put(&i2c_imx->events, EVT_SI);
>> +    case EVT_START:
>> +        atomic_set(&i2c_imx->last_error, -EBUSY);
>> +        break;
>> +    case EVT_STOP:
>> +        break;
>> +    case EVT_ENTRY:
>> +        return 0;
>> +    case EVT_POLL:
>> +        reg = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR);
>> +        if ((reg & I2SR_IBB) && !(reg & I2SR_IAL)) {
>> +
>
> Please drop the empty line above.
agreed
>
>> +            set_state(i2c_imx, STATE_MASTER);
>> +            reg = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
>> +
>> +            i2c_imx->stopped = 0;
>> +            reg |= I2CR_IIEN | I2CR_MTX | I2CR_TXAK;
>> +            reg &= ~I2CR_DMAEN;
>> +            imx_i2c_write_reg(reg, i2c_imx, IMX_I2C_I2CR);
>> +            atomic_set(&i2c_imx->last_error, 0);
>> +            i2c_imx->start_retry_cnt = 0;
>> +            return 0;
>> +        }
>> +        break;
>> +    default:
>> +        break;
>> +
>
> Please drop the empty line above.
agreed
>
>> +    }
>> +
>> +    if (i2c_imx->start_retry_cnt++ < 100) {
>> +        dev_dbg(&i2c_imx->adapter.dev,
>> +            "wait for busy cnt = %i evt = %i",
>> +            i2c_imx->start_retry_cnt, event);
>> +    } else {
>> +
>
> Please drop the empty line above.
agreed
>
>> + dev_dbg(&i2c_imx->adapter.dev, "start timeout");
>> +        i2c_imx->start_retry_cnt = 0;
>> +        atomic_set(&i2c_imx->last_error, -ETIMEDOUT);
>> +        set_state(i2c_imx, STATE_IDLE);
>> +        return STATE_WAIT_TIME;
>> +    }
>> +
>> +    return STATE_MIN_WAIT_TIME;
>> +}
>> +
>> +static void set_state(struct imx_i2c_struct *i2c_imx, unsigned int new)
>> +{
>> +    i2c_imx->state = new;
>> +
>> +    switch (new) {
>> +    case STATE_IDLE:
>> +        idle_evt_handler(i2c_imx, EVT_ENTRY);
>> +        break;
>> +    case STATE_SLAVE:
>> +        slave_evt_handler(i2c_imx, EVT_ENTRY);
>> +        break;
>> +    case STATE_SP:
>> +        sp_evt_handler(i2c_imx, EVT_ENTRY);
>> +        break;
>> +    case STATE_MASTER:
>> +        master_evt_handler(i2c_imx, EVT_ENTRY);
>> +        break;
>> +    }
>> +}
>> +
>> +
>
> Please drop one empty line above.
agreed
>
>> +static int i2c_imx_slave_threadfn(void *pdata)
>> +{
>> +    unsigned int event, delay;
>> +    struct imx_i2c_struct *i2c_imx = (struct imx_i2c_struct *) pdata;
>
> Please remove the cast and swap the lines.
agreed
>
>> +
>> +    do {
>> +
>
> Please drop one empty line above.
agreed
>
>> +        event = evt_get(&i2c_imx->events);
>> +        if (event == EVT_INVALID)
>> +            event = EVT_POLL;
>> +
>> +        switch (i2c_imx->state) {
>> +        case STATE_IDLE:
>> +            delay = idle_evt_handler(i2c_imx, event);
>> +            break;
>> +        case STATE_SLAVE:
>> +            delay = slave_evt_handler(i2c_imx, event);
>> +            break;
>> +        case STATE_SP:
>> +            delay = sp_evt_handler(i2c_imx, event);
>> +            break;
>> +        case STATE_MASTER:
>> +            delay = master_evt_handler(i2c_imx, event);
>> +            break;
>> +        default:
>> +            delay = 0;
>> +            break;
>> +        }
>> +
>> +        if (delay)
>> + wait_event_interruptible_timeout(i2c_imx->state_queue,
>> +                (evt_is_empty(&i2c_imx->events) == 0),
>> +                delay);
>
> I would propose to add here the handling of the return value of
> wait_event_interruptible_timeout()
Do you suggest terminating the thread on on ERESTARTSYS?
>
>> +
>> +    } while (kthread_should_stop() == 0);
>> +
>> +    return 0;
>> +}
>> +
>> +static int i2c_imx_reg_slave(struct i2c_client *slave)
>> +{
>> +    struct imx_i2c_struct *i2c_imx = i2c_get_adapdata(slave->adapter);
>> +    int result;
>> +    struct sched_param param = { .sched_priority = MAX_RT_PRIO - 1 };
>> +
>> +    dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__);
>> +
>> +    if (i2c_imx->slave)
>> +        return -EBUSY;
>> +
>> +    if (slave->flags & I2C_CLIENT_TEN)
>> +        return -EAFNOSUPPORT;
>> +
>> +    i2c_imx->slave = slave;
>> +
>> +    /* Set the Slave address */
>> +    imx_i2c_write_reg((i2c_imx->slave->addr << 1), i2c_imx,
>> IMX_I2C_IADR);
>> +
>> +    result = i2c_imx_hw_start(i2c_imx);
>> +    if (result != 0)
>
> if (result)
agreed
>
>> +        return result;
>> +
>> +    i2c_imx->slave_task = kthread_run(i2c_imx_slave_threadfn,
>> +        (void *)i2c_imx, "i2c-slave-%s", i2c_imx->adapter.name);
>
> (void *) cast is unneeded.
agreed
>
>> +
>> +    sched_setscheduler(i2c_imx->slave_task, SCHED_FIFO, &param);
>
> i2c_imx->slave_task may be set to a ERR_PTR() value, please move this
> line
> after the check for a potential error.
agreed
>
>> +
>> +    if (IS_ERR(i2c_imx->slave_task))
>> +        return PTR_ERR(i2c_imx->slave_task);
>> +
>> +    i2c_imx_slave_init(i2c_imx);
>> +
>> +    return 0;
>> +
>
> Please drop the emtpy line above.
agreed
>
>> +}
>> +
>> +static int i2c_imx_unreg_slave(struct i2c_client *slave)
>> +{
>> +    struct imx_i2c_struct *i2c_imx = i2c_get_adapdata(slave->adapter);
>> +
>> +    dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__);
>> +    if (i2c_imx->slave_task != NULL)
>
> Who does set "i2c_imx->slave_task" to NULL ?
>
> Here it looks like a redundant check, please confirm.
agreed, this function is the only place where it is set to NULL
>
>> + kthread_stop(i2c_imx->slave_task);
>> +
>> +    wake_up(&i2c_imx->state_queue);
>> +
>> +    i2c_imx->slave_task = NULL;
>> +
>> +    i2c_imx->slave = NULL;
>> +
>> +    i2c_imx_stop(i2c_imx);
>> +
>> +    return 0;
>> +}
>> +
>> +
>
> Please drop one of two empty lines above.
agreed
>
>> +#else
>> +
>> +static void evt_init(struct evt_queue *stk)
>> +{
>> +    return;
>> +}
>> +
>> +static unsigned int evt_put(struct evt_queue *stk, unsigned int evt)
>> +{
>> +    return 0;
>> +}
>> +
>> +#endif
>> +
>>  static int i2c_imx_trx_complete(struct imx_i2c_struct *i2c_imx)
>>  {
>> -    wait_event_timeout(i2c_imx->queue, i2c_imx->i2csr & I2SR_IIF, HZ
>> / 10);
>> +    wait_event_timeout(i2c_imx->queue, i2c_imx->master_interrupt,
>> +                STATE_WAIT_TIME);
>>
>> -    if (unlikely(!(i2c_imx->i2csr & I2SR_IIF))) {
>> +    if (unlikely(!(i2c_imx->master_interrupt))) {
>>          dev_dbg(&i2c_imx->adapter.dev, "<%s> Timeout\n", __func__);
>>          return -ETIMEDOUT;
>>      }
>>      dev_dbg(&i2c_imx->adapter.dev, "<%s> TRX complete\n", __func__);
>> -    i2c_imx->i2csr = 0;
>> +    i2c_imx->master_interrupt = 0;
>>      return 0;
>>  }
>>
>> @@ -510,27 +1052,92 @@ static void i2c_imx_set_clk(struct
>> imx_i2c_struct *i2c_imx)
>>  #endif
>>  }
>>
>> +static int i2c_imx_configure_clock(struct imx_i2c_struct *i2c_imx)
>> +{
>> +    int result;
>> +
>> +    i2c_imx_set_clk(i2c_imx);
>> +
>> +    result = clk_prepare_enable(i2c_imx->clk);
>> +    if (result == 0)
>
> if (!result)
agreed
>
>> + imx_i2c_write_reg(i2c_imx->ifdr, i2c_imx, IMX_I2C_IFDR);
>> +
>> +    return result;
>> +}
>> +
>> +static void i2c_imx_enable_i2c_controller(struct imx_i2c_struct
>> *i2c_imx)
>> +{
>> +    imx_i2c_write_reg(i2c_imx->hwdata->i2sr_clr_opcode, i2c_imx,
>> +        IMX_I2C_I2SR);
>> +    imx_i2c_write_reg(i2c_imx->hwdata->i2cr_ien_opcode, i2c_imx,
>> +        IMX_I2C_I2CR);
>> +
>> +    /* Wait controller to be stable */
>> +    udelay(50);
>> +}
>> +
>> +static int i2c_imx_hw_start(struct imx_i2c_struct *i2c_imx)
>> +{
>> +    int result;
>> +
>> +    dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__);
>> +
>> +    result = i2c_imx_configure_clock(i2c_imx);
>> +    if (result != 0)
>> +        return result;
>> +    i2c_imx_enable_i2c_controller(i2c_imx);
>> +    return 0;
>> +}
>> +
>> +
>>  static int i2c_imx_start(struct imx_i2c_struct *i2c_imx)
>>  {
>>      unsigned int temp = 0;
>> -    int result;
>> +    int result, cnt = 0;
>>
>>      dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__);
>>
>> -    i2c_imx_set_clk(i2c_imx);
>> +    if (i2c_imx->slave_task != NULL) {
>
> if (i2c_imx->slave_task)
agreed
>
>>
>> -    imx_i2c_write_reg(i2c_imx->ifdr, i2c_imx, IMX_I2C_IFDR);
>> -    /* Enable I2C controller */
>> -    imx_i2c_write_reg(i2c_imx->hwdata->i2sr_clr_opcode, i2c_imx,
>> IMX_I2C_I2SR);
>> -    imx_i2c_write_reg(i2c_imx->hwdata->i2cr_ien_opcode, i2c_imx,
>> IMX_I2C_I2CR);
>> +        atomic_set(&i2c_imx->last_error, -EUNDEFINED);
>> +        if (evt_put(&i2c_imx->events, EVT_START) != 0) {
>> +            dev_err(&i2c_imx->adapter.dev,
>> +                "Event buffer overflow\n");
>> +            return -EBUSY;
>> +        }
>>
>> -    /* Wait controller to be stable */
>> -    usleep_range(50, 150);
>> +        wake_up(&i2c_imx->state_queue);
>> +
>> +        while ((result = atomic_read(&i2c_imx->last_error)) ==
>> -EUNDEFINED) {
>> +            schedule();
>> +
>> +            /* TODO: debug workaround - start hung monitoring */
>> +            cnt++;
>> +            if (cnt == 500000) {
>> +                dev_err(&i2c_imx->adapter.dev,
>> +                    "Too many start loops\n");
>> + imx_i2c_write_reg(i2c_imx->hwdata->i2cr_ien_opcode ^ I2CR_IEN,
>> +                        i2c_imx, IMX_I2C_I2CR);
>> +                i2c_imx_enable_i2c_controller(i2c_imx);
>> + imx_i2c_write_reg(i2c_imx->hwdata->i2cr_ien_opcode | I2CR_IIEN,
>> +                        i2c_imx, IMX_I2C_I2CR);
>> +
>> +                return -ETIMEDOUT;
>> +            }
>> +
>> +        };
>
> Please drop the trailing semicolon.
agreed
>
>> +        return result;
>> +    }
>> +
>> +    result = i2c_imx_hw_start(i2c_imx);
>> +    if (result != 0)
>
> if (result)
agreed
>
>> +        return result;
>>
>>      /* Start I2C transaction */
>>      temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
>>      temp |= I2CR_MSTA;
>>      imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
>> +
>>      result = i2c_imx_bus_busy(i2c_imx, 1);
>>      if (result)
>>          return result;
>> @@ -542,10 +1149,9 @@ static int i2c_imx_start(struct imx_i2c_struct
>> *i2c_imx)
>>      return result;
>>  }
>>
>> -static void i2c_imx_stop(struct imx_i2c_struct *i2c_imx)
>> +static void i2c_imx_hw_stop(struct imx_i2c_struct *i2c_imx)
>>  {
>>      unsigned int temp = 0;
>> -
>
> Please don't drop this empty line.
agreed
>
>>      if (!i2c_imx->stopped) {
>>          /* Stop I2C transaction */
>>          dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__);
>> @@ -555,6 +1161,7 @@ static void i2c_imx_stop(struct imx_i2c_struct
>> *i2c_imx)
>>              temp &= ~I2CR_DMAEN;
>>          imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
>>      }
>> +
>>      if (is_imx1_i2c(i2c_imx)) {
>>          /*
>>           * This delay caused by an i.MXL hardware bug.
>> @@ -568,24 +1175,58 @@ static void i2c_imx_stop(struct imx_i2c_struct
>> *i2c_imx)
>>          i2c_imx->stopped = 1;
>>      }
>>
>> -    /* Disable I2C controller */
>> -    temp = i2c_imx->hwdata->i2cr_ien_opcode ^ I2CR_IEN,
>> +    temp = i2c_imx->hwdata->i2cr_ien_opcode ^ I2CR_IEN;
>>      imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
>> +
>> +    clk_disable_unprepare(i2c_imx->clk);
>> +
>> +}
>
> Please drop the empty line before closing curly bracket.
agreed
>
>> +
>> +static void i2c_imx_stop(struct imx_i2c_struct *i2c_imx)
>> +{
>> +    if (i2c_imx->slave == NULL) {
>
> if (!i2c_imx->slave)
agreed
>
>> +        i2c_imx_hw_stop(i2c_imx);
>> +    } else {
>> +
>
> Please drop the empty line above.
agreed
>
>> + dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__);
>> +
>> +        evt_put(&i2c_imx->events, EVT_STOP);
>> +        wake_up(&i2c_imx->state_queue);
>> +    }
>> +}
>> +
>> +static void i2c_imx_clear_isr_bit(struct imx_i2c_struct *i2c_imx,
>> +    unsigned int status)
>
> Alignment should match open parenthesis.
agreed
>
>> +{
>> +    status &= ~I2SR_IIF;
>> +    status |= (i2c_imx->hwdata->i2sr_clr_opcode & I2SR_IIF);
>> +    imx_i2c_write_reg(status, i2c_imx, IMX_I2C_I2SR);
>>  }
>>
>> +
>> +
>
> No new empty lines here please.
agreed
>
>>  static irqreturn_t i2c_imx_isr(int irq, void *dev_id)
>>  {
>>      struct imx_i2c_struct *i2c_imx = dev_id;
>> -    unsigned int temp;
>> +    unsigned int status, ctl;
>> +
>> +    status = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR);
>> +    ctl = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
>> +    if (status & I2SR_IIF) {
>> +        i2c_imx_clear_isr_bit(i2c_imx, status);
>> +
>> +        if (ctl & I2CR_MSTA) {
>> +            dev_dbg(&i2c_imx->adapter.dev, "master interrupt");
>> +            i2c_imx->master_interrupt = 1;
>> +            wake_up(&i2c_imx->queue);
>> +        } else if (status & I2SR_IAL) {
>> +            evt_put(&i2c_imx->events, EVT_AL);
>> +        } else {
>> +            dev_dbg(&i2c_imx->adapter.dev, "slave interrupt");
>> +            evt_put(&i2c_imx->events, EVT_SI);
>> +            wake_up(&i2c_imx->state_queue);
>> +        }
>>
>> -    temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR);
>> -    if (temp & I2SR_IIF) {
>> -        /* save status register */
>> -        i2c_imx->i2csr = temp;
>> -        temp &= ~I2SR_IIF;
>> -        temp |= (i2c_imx->hwdata->i2sr_clr_opcode & I2SR_IIF);
>> -        imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2SR);
>> -        wake_up(&i2c_imx->queue);
>>          return IRQ_HANDLED;
>>      }
>>
>> @@ -895,7 +1536,13 @@ static int i2c_imx_xfer(struct i2c_adapter
>> *adapter,
>>
>>      /* Start I2C transfer */
>>      result = i2c_imx_start(i2c_imx);
>> -    if (result) {
>> +    if (result == -ETIMEDOUT) {
>> +        /*
>> +         * Recovery is not started on arbitration lost, since it can
>> +         * break slave transfer. But in case of "bus timeout" recovery
>> +         * it could be useful to bring controller out of "strange
>> state".
>> +         */
>> +        dev_dbg(&i2c_imx->adapter.dev, "call bus recovery");
>>          if (i2c_imx->adapter.bus_recovery_info) {
>>              i2c_recover_bus(&i2c_imx->adapter);
>>              result = i2c_imx_start(i2c_imx);
>> @@ -1040,6 +1687,10 @@ static u32 i2c_imx_func(struct i2c_adapter
>> *adapter)
>>  static struct i2c_algorithm i2c_imx_algo = {
>>      .master_xfer    = i2c_imx_xfer,
>>      .functionality    = i2c_imx_func,
>> +#ifdef CONFIG_I2C_SLAVE
>> +    .reg_slave    = i2c_imx_reg_slave,
>> +    .unreg_slave    = i2c_imx_unreg_slave,
>> +#endif
>>  };
>>
>>  static int i2c_imx_probe(struct platform_device *pdev)
>> @@ -1099,6 +1750,12 @@ static int i2c_imx_probe(struct
>> platform_device *pdev)
>>          return ret;
>>      }
>>
>> +    i2c_imx->pinctrl = devm_pinctrl_get(&pdev->dev);
>> +    if (IS_ERR(i2c_imx->pinctrl)) {
>> +        ret = PTR_ERR(i2c_imx->pinctrl);
>> +        goto clk_disable;
>> +    }
>> +
>
> This change is irrelevant to slave support and questionalble, please
> drop it.
agreed
>
>>      /* Request IRQ */
>>      ret = devm_request_irq(&pdev->dev, irq, i2c_imx_isr, 0,
>>                  pdev->name, i2c_imx);
>> @@ -1109,6 +1766,7 @@ static int i2c_imx_probe(struct platform_device
>> *pdev)
>>
>>      /* Init queue */
>>      init_waitqueue_head(&i2c_imx->queue);
>> +    init_waitqueue_head(&i2c_imx->state_queue);
>>
>>      /* Set up adapter data */
>>      i2c_set_adapdata(&i2c_imx->adapter, i2c_imx);
>> @@ -1160,6 +1818,9 @@ static int i2c_imx_probe(struct platform_device
>> *pdev)
>>      /* Init DMA config if supported */
>>      i2c_imx_dma_request(i2c_imx, phy_addr);
>>
>> +    /* init slave_state to IDLE */
>> +    i2c_imx->state = STATE_IDLE;
>> +    evt_init(&i2c_imx->events);
>
> Please insert an empty line here to impreove readability.
agreed
>
>>      return 0;   /* Return OK */
>>
>>  rpm_disable:
>> @@ -1186,6 +1847,9 @@ static int i2c_imx_remove(struct
>> platform_device *pdev)
>>      dev_dbg(&i2c_imx->adapter.dev, "adapter removed\n");
>>      i2c_del_adapter(&i2c_imx->adapter);
>>
>> +    if (i2c_imx->slave_task != NULL)
>
> if (i2c_imx->slave_task)
agreed
>
>> + kthread_stop(i2c_imx->slave_task);
>> +
>>      if (i2c_imx->dma)
>>          i2c_imx_dma_free(i2c_imx);
>>
>>
>
> The patch contains changes to controller start/stop sequences, this part
> is better to separate into another patch, if possible.
agreed
>
> Review of more important functional changes, which include changes to the
> I2C master functionality, are postponed until we are done with bike
> shedding.
>
> --
> With best wishes,
> Vladimir

-- 
_______________________________________________
Joshua Frkuska | Embedded Software Engineer
Mentor Graphics Japan Co., ltd. | +81-3-6866-7611

PRIVACY AND CONFIDENTIALITY NOTICE
This email and any attachments may contain confidential or privileged 
information for the sole use of the intended recipient.  Any review, 
reliance or distribution by others or forwarding without express 
permission is strictly prohibited.  If you are not the intended 
recipient, please contact the sender and delete all copies.

^ permalink raw reply

* Re: [[RFC V3] 1/1] i2c: imx: add slave support
From: Frkuska, Joshua @ 2016-12-15  0:42 UTC (permalink / raw)
  To: Wolfram Sang; +Cc: linux-i2c, syrchin, peda, vladimir_zapolskiy, Jiada_Wang
In-Reply-To: <20161214133639.GA1476@katana>

Hello Wolfram,

Please see inline. Thank you

On 12/14/2016 10:36 PM, Wolfram Sang wrote:
> On Wed, Dec 14, 2016 at 03:01:31PM +0900, Joshua Frkuska wrote:
>> Add I2C slave provider using the generic slave interface.
>> It also supports master transactions when the slave in the idle mode.
>
> I am confused. In the cover letter you write "Furthermore the state
> machine introduced to handle the slave states does not handle the master
> mode behavior." Yet here you say it supports master transactions? Is the
> sentence from the cover letter outdated?

The cover letter is not outdated but does not elaborate enough. The 
state machine (slave task) operates when I2C_SLAVE is enabled and a 
slave device registered. The slave state machine keeps track of the 
master state but only has two roles relating to master mode. The first 
is to stop the controller when imx_stop is called. The second is to 
transition from an idle state to master mode via a START event. This 
puts the hardware in a possible transition state where the IBB status 
flag hasn't been set yet. To avoid this, the transition 'SP' 
intermediate state is created and we wait for the IBB flag to raise or 
time out after a number of attempts. All other hardware control in 
master mode is done via the i2c_imx_xfer, i2c_imx_start/stop functions. 
When I2C_SLAVE is disabled, the above state machine is not active and 
does serve the STOP event nor does it poll on IBB in this transition 
period. I hope this answers your questions.

>
> Regards,
>
>    Wolfram
>

^ permalink raw reply

* Re: [PATCH] i2c: designware: add reset interface
From: Andy Shevchenko @ 2016-12-14 19:00 UTC (permalink / raw)
  To: Wolfram Sang, Zhangfei Gao
  Cc: linux-arm-kernel, linux-i2c, Jarkko Nikula, Mika Westerberg
In-Reply-To: <20161213203457.GB2889@katana>

On Tue, 2016-12-13 at 21:34 +0100, Wolfram Sang wrote:
> On Tue, Nov 22, 2016 at 12:41:40PM +0800, Zhangfei Gao wrote:
> > Some platforms like hi3660 need do reset first to allow accessing
> > registers
> > 
> > Signed-off-by: Zhangfei Gao <zhangfei.gao@linaro.org>
> 
> Adding designware maintainers to CC...
> 
> > ---
> >  drivers/i2c/busses/i2c-designware-core.h    | 1 +
> >  drivers/i2c/busses/i2c-designware-platdrv.c | 5 +++++
> >  2 files changed, 6 insertions(+)
> > 
> > diff --git a/drivers/i2c/busses/i2c-designware-core.h
> > b/drivers/i2c/busses/i2c-designware-core.h
> > index 0d44d2a..94b14fa 100644
> > --- a/drivers/i2c/busses/i2c-designware-core.h
> > +++ b/drivers/i2c/busses/i2c-designware-core.h
> > @@ -80,6 +80,7 @@ struct dw_i2c_dev {
> >  	void __iomem		*base;
> >  	struct completion	cmd_complete;
> >  	struct clk		*clk;
> > +	struct reset_control	*rst;
> >  	u32			(*get_clk_rate_khz) (struct
> > dw_i2c_dev *dev);
> >  	struct dw_pci_controller *controller;
> >  	int			cmd_err;
> > diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c
> > b/drivers/i2c/busses/i2c-designware-platdrv.c
> > index 0b42a12..fd80e58 100644
> > --- a/drivers/i2c/busses/i2c-designware-platdrv.c
> > +++ b/drivers/i2c/busses/i2c-designware-platdrv.c
> > @@ -38,6 +38,7 @@
> >  #include <linux/pm_runtime.h>
> >  #include <linux/property.h>
> >  #include <linux/io.h>
> > +#include <linux/reset.h>
> >  #include <linux/slab.h>
> >  #include <linux/acpi.h>
> >  #include <linux/platform_data/i2c-designware.h>
> > @@ -176,6 +177,10 @@ static int dw_i2c_plat_probe(struct
> > platform_device *pdev)
> >  	dev->irq = irq;
> >  	platform_set_drvdata(pdev, dev);
> >  
> > +	dev->rst = devm_reset_control_get(&pdev->dev, NULL);
> > +	if (!IS_ERR(dev->rst))
> > +		reset_control_reset(dev->rst);

Do we care about EPROBE_DEFER?

Perhaps on error path we need to assert it.

And I guess it should be devm_reset_control_get_optional().

> > +
> >  	/* fast mode by default because of legacy reasons */
> >  	dev->clk_freq = 400000;
> >  
> > -- 
> > 2.7.4
> > 

-- 
Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Intel Finland Oy

^ permalink raw reply

* Re: [PATCH 1/4] power: supply: axp288_fuel_gauge: Fix fuel_gauge_reg_readb return on error
From: Wolfram Sang @ 2016-12-14 17:01 UTC (permalink / raw)
  To: Hans de Goede
  Cc: Sebastian Reichel, Chen-Yu Tsai, russianneuromancer @ ya . ru,
	linux-pm, linux-i2c
In-Reply-To: <20161214163853.454-1-hdegoede@redhat.com>

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

On Wed, Dec 14, 2016 at 05:38:50PM +0100, Hans de Goede wrote:
> If reading the register fails, return the actual error code, instead
> of the uninitialized val variable;

Please don't CC the linux-i2c list for i2c client drivers unless you
have specific i2c related questions. It makes focussing on the core
parts harder.

Thanks,

   Wolfram


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply

* [PATCH 3/4] power: supply: axp288_fuel_gauge: Read 12 bit values 2 registers at a time
From: Hans de Goede @ 2016-12-14 16:38 UTC (permalink / raw)
  To: Sebastian Reichel, Chen-Yu Tsai
  Cc: russianneuromancer @ ya . ru, linux-pm, linux-i2c, Hans de Goede
In-Reply-To: <20161214163853.454-1-hdegoede@redhat.com>

In order for the MSB -> LSB latching to work correctly we must read the
2 8 bit registers of a 12 bit value in one consecutive read.

This fixes voltage_ocv reporting inconsistent values on my tablet.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
 drivers/power/supply/axp288_fuel_gauge.c | 40 ++++++++++++++++++--------------
 1 file changed, 22 insertions(+), 18 deletions(-)

diff --git a/drivers/power/supply/axp288_fuel_gauge.c b/drivers/power/supply/axp288_fuel_gauge.c
index 99d6d30..089056c 100644
--- a/drivers/power/supply/axp288_fuel_gauge.c
+++ b/drivers/power/supply/axp288_fuel_gauge.c
@@ -210,6 +210,22 @@ static int fuel_gauge_read_15bit_word(struct axp288_fg_info *info, int reg)
 	return ret & FG_15BIT_VAL_MASK;
 }
 
+static int fuel_gauge_read_12bit_word(struct axp288_fg_info *info, int reg)
+{
+	unsigned char buf[2];
+	int ret;
+
+	ret = regmap_bulk_read(info->regmap, reg, buf, 2);
+	if (ret < 0) {
+		dev_err(&info->pdev->dev, "Error reading reg 0x%02x err: %d\n",
+			reg, ret);
+		return ret;
+	}
+
+	/* 12-bit data values have upper 8 bits in buf[0], lower 4 in buf[1] */
+	return (buf[0] << 4) | ((buf[1] >> 4) & 0x0f);
+}
+
 static int pmic_read_adc_val(const char *name, int *raw_val,
 		struct axp288_fg_info *info)
 {
@@ -270,12 +286,9 @@ static int fuel_gauge_debug_show(struct seq_file *s, void *data)
 	seq_printf(s, "    FG_RDC0[%02x] : %02x\n",
 		AXP288_FG_RDC0_REG,
 		fuel_gauge_reg_readb(info, AXP288_FG_RDC0_REG));
-	seq_printf(s, "    FG_OCVH[%02x] : %02x\n",
+	seq_printf(s, "     FG_OCV[%02x] : %04x\n",
 		AXP288_FG_OCVH_REG,
-		fuel_gauge_reg_readb(info, AXP288_FG_OCVH_REG));
-	seq_printf(s, "    FG_OCVL[%02x] : %02x\n",
-		AXP288_FG_OCVL_REG,
-		fuel_gauge_reg_readb(info, AXP288_FG_OCVL_REG));
+		fuel_gauge_read_12bit_word(info, AXP288_FG_OCVH_REG));
 	seq_printf(s, " FG_DES_CAP[%02x] : %04x\n",
 		AXP288_FG_DES_CAP1_REG,
 		fuel_gauge_read_15bit_word(info, AXP288_FG_DES_CAP1_REG));
@@ -532,21 +545,12 @@ static int fuel_gauge_get_btemp(struct axp288_fg_info *info, int *btemp)
 
 static int fuel_gauge_get_vocv(struct axp288_fg_info *info, int *vocv)
 {
-	int ret, value;
-
-	/* 12-bit data value, upper 8 in OCVH, lower 4 in OCVL */
-	ret = fuel_gauge_reg_readb(info, AXP288_FG_OCVH_REG);
-	if (ret < 0)
-		goto vocv_read_fail;
-	value = ret << 4;
+	int ret;
 
-	ret = fuel_gauge_reg_readb(info, AXP288_FG_OCVL_REG);
-	if (ret < 0)
-		goto vocv_read_fail;
-	value |= (ret & 0xf);
+	ret = fuel_gauge_read_12bit_word(info, AXP288_FG_OCVH_REG);
+	if (ret >= 0)
+		*vocv = VOLTAGE_FROM_ADC(ret);
 
-	*vocv = VOLTAGE_FROM_ADC(value);
-vocv_read_fail:
 	return ret;
 }
 
-- 
2.9.3

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox