diff mbox series

[v2,1/5] media: Add MIPI CCI register access helper functions

Message ID 20230614192343.57280-2-hdegoede@redhat.com (mailing list archive)
State New, archived
Headers show
Series media: Add MIPI CCI register access helper functions | expand

Commit Message

Hans de Goede June 14, 2023, 7:23 p.m. UTC
The CSI2 specification specifies a standard method to access camera sensor
registers called "Camera Control Interface (CCI)".

This uses either 8 or 16 bit (big-endian wire order) register addresses
and supports 8, 16, 24 or 32 bit (big-endian wire order) register widths.

Currently a lot of Linux camera sensor drivers all have their own custom
helpers for this, often copy and pasted from other drivers.

Add a set of generic helpers for this so that all sensor drivers can
switch to a single common implementation.

These helpers take an extra optional "int *err" function parameter,
this can be used to chain a bunch of register accesses together with
only a single error check at the end, rather then needing to error
check each individual register access. The first failing call will
set the contents of err to a non 0 value and all other calls will
then become no-ops.

Link: https://lore.kernel.org/linux-media/59aefa7f-7bf9-6736-6040-39551329cd0a@redhat.com/
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
Changes in v2:
- Drop cci_reg_type enum
- Make having an encoded reg-width mandatory rather then using 0 to encode
  8 bit width making reg-addresses without an encoded width default to
  a width of 8
- Add support for 64 bit wide registers
- Introduce a new cci_reg_sequence struct with 64 bit reg values for 64 bit
  support and without the delay_us field
- Various kerneldoc updates
- Stop supporting delays in cci_multi_reg_write()
- Some includes cleanups
- Disable regmap locking
---
 Documentation/driver-api/media/v4l2-cci.rst  |   5 +
 Documentation/driver-api/media/v4l2-core.rst |   1 +
 drivers/media/v4l2-core/Kconfig              |   5 +
 drivers/media/v4l2-core/Makefile             |   1 +
 drivers/media/v4l2-core/v4l2-cci.c           | 157 +++++++++++++++++++
 include/media/v4l2-cci.h                     | 121 ++++++++++++++
 6 files changed, 290 insertions(+)
 create mode 100644 Documentation/driver-api/media/v4l2-cci.rst
 create mode 100644 drivers/media/v4l2-core/v4l2-cci.c
 create mode 100644 include/media/v4l2-cci.h

Comments

Andy Shevchenko June 14, 2023, 8:09 p.m. UTC | #1
On Wed, Jun 14, 2023 at 10:24 PM Hans de Goede <hdegoede@redhat.com> wrote:
>
> The CSI2 specification specifies a standard method to access camera sensor
> registers called "Camera Control Interface (CCI)".
>
> This uses either 8 or 16 bit (big-endian wire order) register addresses
> and supports 8, 16, 24 or 32 bit (big-endian wire order) register widths.
>
> Currently a lot of Linux camera sensor drivers all have their own custom
> helpers for this, often copy and pasted from other drivers.
>
> Add a set of generic helpers for this so that all sensor drivers can
> switch to a single common implementation.
>
> These helpers take an extra optional "int *err" function parameter,
> this can be used to chain a bunch of register accesses together with
> only a single error check at the end, rather then needing to error

than

> check each individual register access. The first failing call will
> set the contents of err to a non 0 value and all other calls will
> then become no-ops.

Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>

In case we need 48-bit accessors, we also have respective
get_unaligned_*48()/put_unaligned_*48() APIs.

> Link: https://lore.kernel.org/linux-media/59aefa7f-7bf9-6736-6040-39551329cd0a@redhat.com/
> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
> ---
> Changes in v2:
> - Drop cci_reg_type enum
> - Make having an encoded reg-width mandatory rather then using 0 to encode
>   8 bit width making reg-addresses without an encoded width default to
>   a width of 8
> - Add support for 64 bit wide registers
> - Introduce a new cci_reg_sequence struct with 64 bit reg values for 64 bit
>   support and without the delay_us field
> - Various kerneldoc updates
> - Stop supporting delays in cci_multi_reg_write()
> - Some includes cleanups
> - Disable regmap locking
> ---
>  Documentation/driver-api/media/v4l2-cci.rst  |   5 +
>  Documentation/driver-api/media/v4l2-core.rst |   1 +
>  drivers/media/v4l2-core/Kconfig              |   5 +
>  drivers/media/v4l2-core/Makefile             |   1 +
>  drivers/media/v4l2-core/v4l2-cci.c           | 157 +++++++++++++++++++
>  include/media/v4l2-cci.h                     | 121 ++++++++++++++
>  6 files changed, 290 insertions(+)
>  create mode 100644 Documentation/driver-api/media/v4l2-cci.rst
>  create mode 100644 drivers/media/v4l2-core/v4l2-cci.c
>  create mode 100644 include/media/v4l2-cci.h
>
> diff --git a/Documentation/driver-api/media/v4l2-cci.rst b/Documentation/driver-api/media/v4l2-cci.rst
> new file mode 100644
> index 000000000000..dd297a40ed20
> --- /dev/null
> +++ b/Documentation/driver-api/media/v4l2-cci.rst
> @@ -0,0 +1,5 @@
> +.. SPDX-License-Identifier: GPL-2.0
> +
> +V4L2 CCI kAPI
> +^^^^^^^^^^^^^
> +.. kernel-doc:: include/media/v4l2-cci.h
> diff --git a/Documentation/driver-api/media/v4l2-core.rst b/Documentation/driver-api/media/v4l2-core.rst
> index 1a8c4a5f256b..239045ecc8f4 100644
> --- a/Documentation/driver-api/media/v4l2-core.rst
> +++ b/Documentation/driver-api/media/v4l2-core.rst
> @@ -22,6 +22,7 @@ Video4Linux devices
>      v4l2-mem2mem
>      v4l2-async
>      v4l2-fwnode
> +    v4l2-cci
>      v4l2-rect
>      v4l2-tuner
>      v4l2-common
> diff --git a/drivers/media/v4l2-core/Kconfig b/drivers/media/v4l2-core/Kconfig
> index 348559bc2468..523ba243261d 100644
> --- a/drivers/media/v4l2-core/Kconfig
> +++ b/drivers/media/v4l2-core/Kconfig
> @@ -74,6 +74,11 @@ config V4L2_FWNODE
>  config V4L2_ASYNC
>         tristate
>
> +config V4L2_CCI
> +       tristate
> +       depends on I2C
> +       select REGMAP_I2C
> +
>  # Used by drivers that need Videobuf modules
>  config VIDEOBUF_GEN
>         tristate
> diff --git a/drivers/media/v4l2-core/Makefile b/drivers/media/v4l2-core/Makefile
> index 41d91bd10cf2..be2551705755 100644
> --- a/drivers/media/v4l2-core/Makefile
> +++ b/drivers/media/v4l2-core/Makefile
> @@ -25,6 +25,7 @@ videodev-$(CONFIG_VIDEO_V4L2_I2C) += v4l2-i2c.o
>  # (e. g. LC_ALL=C sort Makefile)
>
>  obj-$(CONFIG_V4L2_ASYNC) += v4l2-async.o
> +obj-$(CONFIG_V4L2_CCI) += v4l2-cci.o
>  obj-$(CONFIG_V4L2_FLASH_LED_CLASS) += v4l2-flash-led-class.o
>  obj-$(CONFIG_V4L2_FWNODE) += v4l2-fwnode.o
>  obj-$(CONFIG_V4L2_H264) += v4l2-h264.o
> diff --git a/drivers/media/v4l2-core/v4l2-cci.c b/drivers/media/v4l2-core/v4l2-cci.c
> new file mode 100644
> index 000000000000..94764f3ebc6c
> --- /dev/null
> +++ b/drivers/media/v4l2-core/v4l2-cci.c
> @@ -0,0 +1,157 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * MIPI Camera Control Interface (CCI) register access helpers.
> + *
> + * Copyright (C) 2023 Hans de Goede <hansg@kernel.org>
> + */
> +
> +#include <linux/bitfield.h>
> +#include <linux/delay.h>
> +#include <linux/dev_printk.h>
> +#include <linux/module.h>
> +#include <linux/regmap.h>
> +#include <linux/types.h>
> +
> +#include <asm/unaligned.h>
> +
> +#include <media/v4l2-cci.h>
> +
> +int cci_read(struct regmap *map, u32 reg, u64 *val, int *err)
> +{
> +       int len, ret;
> +       u8 buf[8];
> +
> +       if (err && *err)
> +               return *err;
> +
> +       len = FIELD_GET(CCI_REG_WIDTH_MASK, reg);
> +       reg = FIELD_GET(CCI_REG_ADDR_MASK, reg);
> +
> +       ret = regmap_bulk_read(map, reg, buf, len);
> +       if (ret) {
> +               dev_err(regmap_get_device(map), "Error reading reg 0x%4x: %d\n", reg, ret);
> +               goto out;
> +       }
> +
> +       switch (len) {
> +       case 1:
> +               *val = buf[0];
> +               break;
> +       case 2:
> +               *val = get_unaligned_be16(buf);
> +               break;
> +       case 3:
> +               *val = get_unaligned_be24(buf);
> +               break;
> +       case 4:
> +               *val = get_unaligned_be32(buf);
> +               break;
> +       case 8:
> +               *val = get_unaligned_be64(buf);
> +               break;
> +       default:
> +               dev_err(regmap_get_device(map), "Error invalid reg-width %d for reg 0x%04x\n",
> +                       len, reg);
> +               ret = -EINVAL;
> +               break;
> +       }
> +
> +out:
> +       if (ret && err)
> +               *err = ret;
> +
> +       return ret;
> +}
> +EXPORT_SYMBOL_GPL(cci_read);
> +
> +int cci_write(struct regmap *map, u32 reg, u64 val, int *err)
> +{
> +       int len, ret;
> +       u8 buf[8];
> +
> +       if (err && *err)
> +               return *err;
> +
> +       len = FIELD_GET(CCI_REG_WIDTH_MASK, reg);
> +       reg = FIELD_GET(CCI_REG_ADDR_MASK, reg);
> +
> +       switch (len) {
> +       case 1:
> +               buf[0] = val;
> +               break;
> +       case 2:
> +               put_unaligned_be16(val, buf);
> +               break;
> +       case 3:
> +               put_unaligned_be24(val, buf);
> +               break;
> +       case 4:
> +               put_unaligned_be32(val, buf);
> +               break;
> +       case 8:
> +               put_unaligned_be64(val, buf);
> +               break;
> +       default:
> +               dev_err(regmap_get_device(map), "Error invalid reg-width %d for reg 0x%04x\n",
> +                       len, reg);
> +               ret = -EINVAL;
> +               goto out;
> +       }
> +
> +       ret = regmap_bulk_write(map, reg, buf, len);
> +       if (ret)
> +               dev_err(regmap_get_device(map), "Error writing reg 0x%4x: %d\n", reg, ret);
> +
> +out:
> +       if (ret && err)
> +               *err = ret;
> +
> +       return ret;
> +}
> +EXPORT_SYMBOL_GPL(cci_write);
> +
> +int cci_update_bits(struct regmap *map, u32 reg, u64 mask, u64 val, int *err)
> +{
> +       u64 readval;
> +       int ret;
> +
> +       ret = cci_read(map, reg, &readval, err);
> +       if (ret)
> +               return ret;
> +
> +       val = (readval & ~mask) | (val & mask);
> +
> +       return cci_write(map, reg, val, err);
> +}
> +EXPORT_SYMBOL_GPL(cci_update_bits);
> +
> +int cci_multi_reg_write(struct regmap *map, const struct cci_reg_sequence *regs,
> +                       int num_regs, int *err)
> +{
> +       int i, ret;
> +
> +       for (i = 0; i < num_regs; i++) {
> +               ret = cci_write(map, regs[i].reg, regs[i].val, err);
> +               if (ret)
> +                       return ret;
> +       }
> +
> +       return 0;
> +}
> +EXPORT_SYMBOL_GPL(cci_multi_reg_write);
> +
> +struct regmap *cci_regmap_init_i2c(struct i2c_client *client, int reg_addr_bits)
> +{
> +       struct regmap_config config = {
> +               .reg_bits = reg_addr_bits,
> +               .val_bits = 8,
> +               .reg_format_endian = REGMAP_ENDIAN_BIG,
> +               .disable_locking = true,
> +       };
> +
> +       return devm_regmap_init_i2c(client, &config);
> +}
> +EXPORT_SYMBOL_GPL(cci_regmap_init_i2c);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_AUTHOR("Hans de Goede <hansg@kernel.org>");
> diff --git a/include/media/v4l2-cci.h b/include/media/v4l2-cci.h
> new file mode 100644
> index 000000000000..5d8fdff086db
> --- /dev/null
> +++ b/include/media/v4l2-cci.h
> @@ -0,0 +1,121 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * MIPI Camera Control Interface (CCI) register access helpers.
> + *
> + * Copyright (C) 2023 Hans de Goede <hansg@kernel.org>
> + */
> +#ifndef _V4L2_CCI_H
> +#define _V4L2_CCI_H
> +
> +#include <linux/types.h>
> +
> +struct i2c_client;
> +struct reg_sequence;
> +struct regmap;
> +
> +/**
> + * struct cci_reg_sequence - An individual write from a sequence of CCI writes
> + *
> + * @reg: Register address, use CCI_REG#() macros to encode reg width
> + * @val: Register value
> + *
> + * Register/value pairs for sequences of writes.
> + */
> +struct cci_reg_sequence {
> +       u32 reg;
> +       u64 val;
> +};
> +
> +/*
> + * Macros to define register address with the register width encoded
> + * into the higher bits.
> + */
> +#define CCI_REG_ADDR_MASK              GENMASK(15, 0)
> +#define CCI_REG_WIDTH_SHIFT            16
> +#define CCI_REG_WIDTH_MASK             GENMASK(19, 16)
> +
> +#define CCI_REG8(x)                    ((1 << CCI_REG_WIDTH_SHIFT) | (x))
> +#define CCI_REG16(x)                   ((2 << CCI_REG_WIDTH_SHIFT) | (x))
> +#define CCI_REG24(x)                   ((3 << CCI_REG_WIDTH_SHIFT) | (x))
> +#define CCI_REG32(x)                   ((4 << CCI_REG_WIDTH_SHIFT) | (x))
> +#define CCI_REG64(x)                   ((8 << CCI_REG_WIDTH_SHIFT) | (x))
> +
> +/**
> + * cci_read() - Read a value from a single CCI register
> + *
> + * @map: Register map to read from
> + * @reg: Register address to read, use CCI_REG#() macros to encode reg width
> + * @val: Pointer to store read value
> + * @err: optional pointer to store errors, if a previous error is set
> + *       then the read will be skipped
> + *
> + * Return: %0 on success or a negative error code on failure.
> + */
> +int cci_read(struct regmap *map, u32 reg, u64 *val, int *err);
> +
> +/**
> + * cci_write() - Write a value to a single CCI register
> + *
> + * @map: Register map to write to
> + * @reg: Register address to write, use CCI_REG#() macros to encode reg width
> + * @val: Value to be written
> + * @err: optional pointer to store errors, if a previous error is set
> + *       then the write will be skipped
> + *
> + * Return: %0 on success or a negative error code on failure.
> + */
> +int cci_write(struct regmap *map, u32 reg, u64 val, int *err);
> +
> +/**
> + * cci_update_bits() - Perform a read/modify/write cycle on a single CCI register
> + *
> + * @map: Register map to update
> + * @reg: Register address to update, use CCI_REG#() macros to encode reg width
> + * @mask: Bitmask to change
> + * @val: New value for bitmask
> + * @err: optional pointer to store errors, if a previous error is set
> + *       then the update will be skipped
> + *
> + * Note this uses read-modify-write to update the bits, atomicity wrt other
> + * cci_*() register access functions is NOT guaranteed.
> + *
> + * Return: %0 on success or a negative error code on failure.
> + */
> +int cci_update_bits(struct regmap *map, u32 reg, u64 mask, u64 val, int *err);
> +
> +/**
> + * cci_multi_reg_write() - Write multiple registers to the device
> + *
> + * @map: Register map to write to
> + * @regs: Array of structures containing register-address, value pairs to be written
> + *        register-addresses use CCI_REG#() macros to encode reg width
> + * @num_regs: Number of registers to write
> + * @err: optional pointer to store errors, if a previous error is set
> + *       then the write will be skipped
> + *
> + * Write multiple registers to the device where the set of register, value
> + * pairs are supplied in any order, possibly not all in a single range.
> + *
> + * Use of the CCI_REG#() macros to encode reg width is mandatory.
> + *
> + * For raw lists of register-address, -value pairs with only 8 bit
> + * wide writes regmap_multi_reg_write() can be used instead.
> + *
> + * Return: %0 on success or a negative error code on failure.
> + */
> +int cci_multi_reg_write(struct regmap *map, const struct cci_reg_sequence *regs,
> +                       int num_regs, int *err);
> +
> +/**
> + * cci_regmap_init_i2c() - Create regmap to use with cci_*() register access functions
> + *
> + * @client: i2c_client to create the regmap for
> + * @reg_addr_bits: register address width to use (8 or 16)
> + *
> + * Note the memory for the created regmap is devm() managed, tied to the client.
> + *
> + * Return: %0 on success or a negative error code on failure.
> + */
> +struct regmap *cci_regmap_init_i2c(struct i2c_client *client, int reg_addr_bits);
> +
> +#endif
> --
> 2.40.1
>
Sakari Ailus June 14, 2023, 8:39 p.m. UTC | #2
Hi Hans,

Thank you for the update.

On Wed, Jun 14, 2023 at 09:23:39PM +0200, Hans de Goede wrote:
> The CSI2 specification specifies a standard method to access camera sensor
> registers called "Camera Control Interface (CCI)".
> 
> This uses either 8 or 16 bit (big-endian wire order) register addresses
> and supports 8, 16, 24 or 32 bit (big-endian wire order) register widths.
> 
> Currently a lot of Linux camera sensor drivers all have their own custom
> helpers for this, often copy and pasted from other drivers.
> 
> Add a set of generic helpers for this so that all sensor drivers can
> switch to a single common implementation.
> 
> These helpers take an extra optional "int *err" function parameter,
> this can be used to chain a bunch of register accesses together with
> only a single error check at the end, rather then needing to error
> check each individual register access. The first failing call will
> set the contents of err to a non 0 value and all other calls will
> then become no-ops.
> 
> Link: https://lore.kernel.org/linux-media/59aefa7f-7bf9-6736-6040-39551329cd0a@redhat.com/
> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
> ---
> Changes in v2:
> - Drop cci_reg_type enum
> - Make having an encoded reg-width mandatory rather then using 0 to encode
>   8 bit width making reg-addresses without an encoded width default to
>   a width of 8
> - Add support for 64 bit wide registers
> - Introduce a new cci_reg_sequence struct with 64 bit reg values for 64 bit
>   support and without the delay_us field
> - Various kerneldoc updates
> - Stop supporting delays in cci_multi_reg_write()
> - Some includes cleanups
> - Disable regmap locking
> ---
>  Documentation/driver-api/media/v4l2-cci.rst  |   5 +
>  Documentation/driver-api/media/v4l2-core.rst |   1 +
>  drivers/media/v4l2-core/Kconfig              |   5 +
>  drivers/media/v4l2-core/Makefile             |   1 +
>  drivers/media/v4l2-core/v4l2-cci.c           | 157 +++++++++++++++++++
>  include/media/v4l2-cci.h                     | 121 ++++++++++++++
>  6 files changed, 290 insertions(+)
>  create mode 100644 Documentation/driver-api/media/v4l2-cci.rst
>  create mode 100644 drivers/media/v4l2-core/v4l2-cci.c
>  create mode 100644 include/media/v4l2-cci.h
> 
> diff --git a/Documentation/driver-api/media/v4l2-cci.rst b/Documentation/driver-api/media/v4l2-cci.rst
> new file mode 100644
> index 000000000000..dd297a40ed20
> --- /dev/null
> +++ b/Documentation/driver-api/media/v4l2-cci.rst
> @@ -0,0 +1,5 @@
> +.. SPDX-License-Identifier: GPL-2.0
> +
> +V4L2 CCI kAPI
> +^^^^^^^^^^^^^
> +.. kernel-doc:: include/media/v4l2-cci.h
> diff --git a/Documentation/driver-api/media/v4l2-core.rst b/Documentation/driver-api/media/v4l2-core.rst
> index 1a8c4a5f256b..239045ecc8f4 100644
> --- a/Documentation/driver-api/media/v4l2-core.rst
> +++ b/Documentation/driver-api/media/v4l2-core.rst
> @@ -22,6 +22,7 @@ Video4Linux devices
>      v4l2-mem2mem
>      v4l2-async
>      v4l2-fwnode
> +    v4l2-cci
>      v4l2-rect
>      v4l2-tuner
>      v4l2-common
> diff --git a/drivers/media/v4l2-core/Kconfig b/drivers/media/v4l2-core/Kconfig
> index 348559bc2468..523ba243261d 100644
> --- a/drivers/media/v4l2-core/Kconfig
> +++ b/drivers/media/v4l2-core/Kconfig
> @@ -74,6 +74,11 @@ config V4L2_FWNODE
>  config V4L2_ASYNC
>  	tristate
>  
> +config V4L2_CCI
> +	tristate
> +	depends on I2C

This won't do anything if the dependent driver will select V4L2_CCI, will
it? I'd let the sensor driver depend on I2C instead. CCI is also supported
on I3C, for instance.

> +	select REGMAP_I2C

This is a good question.

How about adding V4L2_CCI_I2C that would select REGMAP_I2C?

> +
>  # Used by drivers that need Videobuf modules
>  config VIDEOBUF_GEN
>  	tristate
> diff --git a/drivers/media/v4l2-core/Makefile b/drivers/media/v4l2-core/Makefile
> index 41d91bd10cf2..be2551705755 100644
> --- a/drivers/media/v4l2-core/Makefile
> +++ b/drivers/media/v4l2-core/Makefile
> @@ -25,6 +25,7 @@ videodev-$(CONFIG_VIDEO_V4L2_I2C) += v4l2-i2c.o
>  # (e. g. LC_ALL=C sort Makefile)
>  
>  obj-$(CONFIG_V4L2_ASYNC) += v4l2-async.o
> +obj-$(CONFIG_V4L2_CCI) += v4l2-cci.o
>  obj-$(CONFIG_V4L2_FLASH_LED_CLASS) += v4l2-flash-led-class.o
>  obj-$(CONFIG_V4L2_FWNODE) += v4l2-fwnode.o
>  obj-$(CONFIG_V4L2_H264) += v4l2-h264.o
> diff --git a/drivers/media/v4l2-core/v4l2-cci.c b/drivers/media/v4l2-core/v4l2-cci.c
> new file mode 100644
> index 000000000000..94764f3ebc6c
> --- /dev/null
> +++ b/drivers/media/v4l2-core/v4l2-cci.c
> @@ -0,0 +1,157 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * MIPI Camera Control Interface (CCI) register access helpers.
> + *
> + * Copyright (C) 2023 Hans de Goede <hansg@kernel.org>
> + */
> +
> +#include <linux/bitfield.h>
> +#include <linux/delay.h>
> +#include <linux/dev_printk.h>
> +#include <linux/module.h>
> +#include <linux/regmap.h>
> +#include <linux/types.h>
> +
> +#include <asm/unaligned.h>
> +
> +#include <media/v4l2-cci.h>
> +
> +int cci_read(struct regmap *map, u32 reg, u64 *val, int *err)
> +{
> +	int len, ret;

len would look better unsigned.

> +	u8 buf[8];
> +
> +	if (err && *err)
> +		return *err;
> +
> +	len = FIELD_GET(CCI_REG_WIDTH_MASK, reg);
> +	reg = FIELD_GET(CCI_REG_ADDR_MASK, reg);
> +
> +	ret = regmap_bulk_read(map, reg, buf, len);
> +	if (ret) {
> +		dev_err(regmap_get_device(map), "Error reading reg 0x%4x: %d\n", reg, ret);
> +		goto out;
> +	}
> +
> +	switch (len) {
> +	case 1:
> +		*val = buf[0];
> +		break;
> +	case 2:
> +		*val = get_unaligned_be16(buf);
> +		break;
> +	case 3:
> +		*val = get_unaligned_be24(buf);
> +		break;
> +	case 4:
> +		*val = get_unaligned_be32(buf);
> +		break;
> +	case 8:
> +		*val = get_unaligned_be64(buf);
> +		break;
> +	default:
> +		dev_err(regmap_get_device(map), "Error invalid reg-width %d for reg 0x%04x\n",
> +			len, reg);
> +		ret = -EINVAL;
> +		break;
> +	}
> +
> +out:
> +	if (ret && err)
> +		*err = ret;
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(cci_read);
> +
> +int cci_write(struct regmap *map, u32 reg, u64 val, int *err)
> +{
> +	int len, ret;

Same here.

> +	u8 buf[8];
> +
> +	if (err && *err)
> +		return *err;
> +
> +	len = FIELD_GET(CCI_REG_WIDTH_MASK, reg);
> +	reg = FIELD_GET(CCI_REG_ADDR_MASK, reg);
> +
> +	switch (len) {
> +	case 1:
> +		buf[0] = val;
> +		break;
> +	case 2:
> +		put_unaligned_be16(val, buf);
> +		break;
> +	case 3:
> +		put_unaligned_be24(val, buf);
> +		break;
> +	case 4:
> +		put_unaligned_be32(val, buf);
> +		break;
> +	case 8:
> +		put_unaligned_be64(val, buf);
> +		break;
> +	default:
> +		dev_err(regmap_get_device(map), "Error invalid reg-width %d for reg 0x%04x\n",
> +			len, reg);
> +		ret = -EINVAL;
> +		goto out;
> +	}
> +
> +	ret = regmap_bulk_write(map, reg, buf, len);
> +	if (ret)
> +		dev_err(regmap_get_device(map), "Error writing reg 0x%4x: %d\n", reg, ret);
> +
> +out:
> +	if (ret && err)
> +		*err = ret;
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(cci_write);
> +
> +int cci_update_bits(struct regmap *map, u32 reg, u64 mask, u64 val, int *err)
> +{
> +	u64 readval;
> +	int ret;
> +
> +	ret = cci_read(map, reg, &readval, err);
> +	if (ret)
> +		return ret;
> +
> +	val = (readval & ~mask) | (val & mask);
> +
> +	return cci_write(map, reg, val, err);
> +}
> +EXPORT_SYMBOL_GPL(cci_update_bits);
> +
> +int cci_multi_reg_write(struct regmap *map, const struct cci_reg_sequence *regs,
> +			int num_regs, int *err)
> +{
> +	int i, ret;

unsigned int i?

Same for num_regs.

> +
> +	for (i = 0; i < num_regs; i++) {
> +		ret = cci_write(map, regs[i].reg, regs[i].val, err);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(cci_multi_reg_write);
> +
> +struct regmap *cci_regmap_init_i2c(struct i2c_client *client, int reg_addr_bits)
> +{
> +	struct regmap_config config = {
> +		.reg_bits = reg_addr_bits,
> +		.val_bits = 8,
> +		.reg_format_endian = REGMAP_ENDIAN_BIG,
> +		.disable_locking = true,
> +	};
> +
> +	return devm_regmap_init_i2c(client, &config);
> +}
> +EXPORT_SYMBOL_GPL(cci_regmap_init_i2c);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_AUTHOR("Hans de Goede <hansg@kernel.org>");
> diff --git a/include/media/v4l2-cci.h b/include/media/v4l2-cci.h
> new file mode 100644
> index 000000000000..5d8fdff086db
> --- /dev/null
> +++ b/include/media/v4l2-cci.h
> @@ -0,0 +1,121 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * MIPI Camera Control Interface (CCI) register access helpers.
> + *
> + * Copyright (C) 2023 Hans de Goede <hansg@kernel.org>
> + */
> +#ifndef _V4L2_CCI_H
> +#define _V4L2_CCI_H
> +
> +#include <linux/types.h>
> +
> +struct i2c_client;
> +struct reg_sequence;
> +struct regmap;
> +
> +/**
> + * struct cci_reg_sequence - An individual write from a sequence of CCI writes
> + *
> + * @reg: Register address, use CCI_REG#() macros to encode reg width
> + * @val: Register value
> + *
> + * Register/value pairs for sequences of writes.
> + */
> +struct cci_reg_sequence {
> +	u32 reg;
> +	u64 val;
> +};
> +
> +/*
> + * Macros to define register address with the register width encoded
> + * into the higher bits.
> + */
> +#define CCI_REG_ADDR_MASK		GENMASK(15, 0)
> +#define CCI_REG_WIDTH_SHIFT		16
> +#define CCI_REG_WIDTH_MASK		GENMASK(19, 16)
> +
> +#define CCI_REG8(x)			((1 << CCI_REG_WIDTH_SHIFT) | (x))
> +#define CCI_REG16(x)			((2 << CCI_REG_WIDTH_SHIFT) | (x))
> +#define CCI_REG24(x)			((3 << CCI_REG_WIDTH_SHIFT) | (x))
> +#define CCI_REG32(x)			((4 << CCI_REG_WIDTH_SHIFT) | (x))
> +#define CCI_REG64(x)			((8 << CCI_REG_WIDTH_SHIFT) | (x))
> +
> +/**
> + * cci_read() - Read a value from a single CCI register
> + *
> + * @map: Register map to read from
> + * @reg: Register address to read, use CCI_REG#() macros to encode reg width
> + * @val: Pointer to store read value
> + * @err: optional pointer to store errors, if a previous error is set
> + *       then the read will be skipped
> + *
> + * Return: %0 on success or a negative error code on failure.
> + */
> +int cci_read(struct regmap *map, u32 reg, u64 *val, int *err);
> +
> +/**
> + * cci_write() - Write a value to a single CCI register
> + *
> + * @map: Register map to write to
> + * @reg: Register address to write, use CCI_REG#() macros to encode reg width
> + * @val: Value to be written
> + * @err: optional pointer to store errors, if a previous error is set
> + *       then the write will be skipped
> + *
> + * Return: %0 on success or a negative error code on failure.
> + */
> +int cci_write(struct regmap *map, u32 reg, u64 val, int *err);
> +
> +/**
> + * cci_update_bits() - Perform a read/modify/write cycle on a single CCI register
> + *
> + * @map: Register map to update
> + * @reg: Register address to update, use CCI_REG#() macros to encode reg width
> + * @mask: Bitmask to change
> + * @val: New value for bitmask
> + * @err: optional pointer to store errors, if a previous error is set
> + *       then the update will be skipped
> + *
> + * Note this uses read-modify-write to update the bits, atomicity wrt other
> + * cci_*() register access functions is NOT guaranteed.
> + *
> + * Return: %0 on success or a negative error code on failure.
> + */
> +int cci_update_bits(struct regmap *map, u32 reg, u64 mask, u64 val, int *err);
> +
> +/**
> + * cci_multi_reg_write() - Write multiple registers to the device
> + *
> + * @map: Register map to write to
> + * @regs: Array of structures containing register-address, value pairs to be written
> + *        register-addresses use CCI_REG#() macros to encode reg width
> + * @num_regs: Number of registers to write
> + * @err: optional pointer to store errors, if a previous error is set
> + *       then the write will be skipped
> + *
> + * Write multiple registers to the device where the set of register, value
> + * pairs are supplied in any order, possibly not all in a single range.
> + *
> + * Use of the CCI_REG#() macros to encode reg width is mandatory.
> + *
> + * For raw lists of register-address, -value pairs with only 8 bit
> + * wide writes regmap_multi_reg_write() can be used instead.
> + *
> + * Return: %0 on success or a negative error code on failure.
> + */
> +int cci_multi_reg_write(struct regmap *map, const struct cci_reg_sequence *regs,
> +			int num_regs, int *err);
> +
> +/**
> + * cci_regmap_init_i2c() - Create regmap to use with cci_*() register access functions
> + *
> + * @client: i2c_client to create the regmap for
> + * @reg_addr_bits: register address width to use (8 or 16)
> + *
> + * Note the memory for the created regmap is devm() managed, tied to the client.
> + *
> + * Return: %0 on success or a negative error code on failure.
> + */
> +struct regmap *cci_regmap_init_i2c(struct i2c_client *client, int reg_addr_bits);
> +
> +#endif

Could you run

	./scripts/checkpatch.pl --strict --max-line-length=80

on this?
Laurent Pinchart June 14, 2023, 9:34 p.m. UTC | #3
Hello,

On Wed, Jun 14, 2023 at 08:39:56PM +0000, Sakari Ailus wrote:
> On Wed, Jun 14, 2023 at 09:23:39PM +0200, Hans de Goede wrote:
> > The CSI2 specification specifies a standard method to access camera sensor
> > registers called "Camera Control Interface (CCI)".
> > 
> > This uses either 8 or 16 bit (big-endian wire order) register addresses
> > and supports 8, 16, 24 or 32 bit (big-endian wire order) register widths.
> > 
> > Currently a lot of Linux camera sensor drivers all have their own custom
> > helpers for this, often copy and pasted from other drivers.
> > 
> > Add a set of generic helpers for this so that all sensor drivers can
> > switch to a single common implementation.
> > 
> > These helpers take an extra optional "int *err" function parameter,
> > this can be used to chain a bunch of register accesses together with
> > only a single error check at the end, rather then needing to error
> > check each individual register access. The first failing call will
> > set the contents of err to a non 0 value and all other calls will
> > then become no-ops.
> > 
> > Link: https://lore.kernel.org/linux-media/59aefa7f-7bf9-6736-6040-39551329cd0a@redhat.com/
> > Signed-off-by: Hans de Goede <hdegoede@redhat.com>
> > ---
> > Changes in v2:
> > - Drop cci_reg_type enum
> > - Make having an encoded reg-width mandatory rather then using 0 to encode
> >   8 bit width making reg-addresses without an encoded width default to
> >   a width of 8
> > - Add support for 64 bit wide registers

I'm in two minds about this. This means that the read and write
functions take a u64 argument, which will be less efficient on 32-bit
platforms. I think it would be possible, with some macro magic, to
accept different argument sizes, but maybe that's a micro-optimization
that would actually result in worse code. 

64-bit support could be useful, but as far as I can tell, it's not used
in this series, so maybe we could leave this for later ?

> > - Introduce a new cci_reg_sequence struct with 64 bit reg values for 64 bit
> >   support and without the delay_us field

This consumes extra memory too. Is it an issue ?

> > - Various kerneldoc updates
> > - Stop supporting delays in cci_multi_reg_write()
> > - Some includes cleanups
> > - Disable regmap locking
> > ---
> >  Documentation/driver-api/media/v4l2-cci.rst  |   5 +
> >  Documentation/driver-api/media/v4l2-core.rst |   1 +
> >  drivers/media/v4l2-core/Kconfig              |   5 +
> >  drivers/media/v4l2-core/Makefile             |   1 +
> >  drivers/media/v4l2-core/v4l2-cci.c           | 157 +++++++++++++++++++
> >  include/media/v4l2-cci.h                     | 121 ++++++++++++++
> >  6 files changed, 290 insertions(+)
> >  create mode 100644 Documentation/driver-api/media/v4l2-cci.rst
> >  create mode 100644 drivers/media/v4l2-core/v4l2-cci.c
> >  create mode 100644 include/media/v4l2-cci.h
> > 
> > diff --git a/Documentation/driver-api/media/v4l2-cci.rst b/Documentation/driver-api/media/v4l2-cci.rst
> > new file mode 100644
> > index 000000000000..dd297a40ed20
> > --- /dev/null
> > +++ b/Documentation/driver-api/media/v4l2-cci.rst
> > @@ -0,0 +1,5 @@
> > +.. SPDX-License-Identifier: GPL-2.0
> > +
> > +V4L2 CCI kAPI
> > +^^^^^^^^^^^^^
> > +.. kernel-doc:: include/media/v4l2-cci.h
> > diff --git a/Documentation/driver-api/media/v4l2-core.rst b/Documentation/driver-api/media/v4l2-core.rst
> > index 1a8c4a5f256b..239045ecc8f4 100644
> > --- a/Documentation/driver-api/media/v4l2-core.rst
> > +++ b/Documentation/driver-api/media/v4l2-core.rst
> > @@ -22,6 +22,7 @@ Video4Linux devices
> >      v4l2-mem2mem
> >      v4l2-async
> >      v4l2-fwnode
> > +    v4l2-cci
> >      v4l2-rect
> >      v4l2-tuner
> >      v4l2-common
> > diff --git a/drivers/media/v4l2-core/Kconfig b/drivers/media/v4l2-core/Kconfig
> > index 348559bc2468..523ba243261d 100644
> > --- a/drivers/media/v4l2-core/Kconfig
> > +++ b/drivers/media/v4l2-core/Kconfig
> > @@ -74,6 +74,11 @@ config V4L2_FWNODE
> >  config V4L2_ASYNC
> >  	tristate
> >  
> > +config V4L2_CCI
> > +	tristate
> > +	depends on I2C
> 
> This won't do anything if the dependent driver will select V4L2_CCI, will
> it? I'd let the sensor driver depend on I2C instead. CCI is also supported
> on I3C, for instance.
> 
> > +	select REGMAP_I2C
> 
> This is a good question.
> 
> How about adding V4L2_CCI_I2C that would select REGMAP_I2C?
> 
> > +
> >  # Used by drivers that need Videobuf modules
> >  config VIDEOBUF_GEN
> >  	tristate
> > diff --git a/drivers/media/v4l2-core/Makefile b/drivers/media/v4l2-core/Makefile
> > index 41d91bd10cf2..be2551705755 100644
> > --- a/drivers/media/v4l2-core/Makefile
> > +++ b/drivers/media/v4l2-core/Makefile
> > @@ -25,6 +25,7 @@ videodev-$(CONFIG_VIDEO_V4L2_I2C) += v4l2-i2c.o
> >  # (e. g. LC_ALL=C sort Makefile)
> >  
> >  obj-$(CONFIG_V4L2_ASYNC) += v4l2-async.o
> > +obj-$(CONFIG_V4L2_CCI) += v4l2-cci.o
> >  obj-$(CONFIG_V4L2_FLASH_LED_CLASS) += v4l2-flash-led-class.o
> >  obj-$(CONFIG_V4L2_FWNODE) += v4l2-fwnode.o
> >  obj-$(CONFIG_V4L2_H264) += v4l2-h264.o
> > diff --git a/drivers/media/v4l2-core/v4l2-cci.c b/drivers/media/v4l2-core/v4l2-cci.c
> > new file mode 100644
> > index 000000000000..94764f3ebc6c
> > --- /dev/null
> > +++ b/drivers/media/v4l2-core/v4l2-cci.c
> > @@ -0,0 +1,157 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * MIPI Camera Control Interface (CCI) register access helpers.
> > + *
> > + * Copyright (C) 2023 Hans de Goede <hansg@kernel.org>
> > + */
> > +
> > +#include <linux/bitfield.h>
> > +#include <linux/delay.h>
> > +#include <linux/dev_printk.h>
> > +#include <linux/module.h>
> > +#include <linux/regmap.h>
> > +#include <linux/types.h>
> > +
> > +#include <asm/unaligned.h>
> > +
> > +#include <media/v4l2-cci.h>
> > +
> > +int cci_read(struct regmap *map, u32 reg, u64 *val, int *err)
> > +{
> > +	int len, ret;
> 
> len would look better unsigned.
> 
> > +	u8 buf[8];
> > +
> > +	if (err && *err)
> > +		return *err;
> > +
> > +	len = FIELD_GET(CCI_REG_WIDTH_MASK, reg);
> > +	reg = FIELD_GET(CCI_REG_ADDR_MASK, reg);
> > +
> > +	ret = regmap_bulk_read(map, reg, buf, len);
> > +	if (ret) {
> > +		dev_err(regmap_get_device(map), "Error reading reg 0x%4x: %d\n", reg, ret);
> > +		goto out;
> > +	}
> > +
> > +	switch (len) {
> > +	case 1:
> > +		*val = buf[0];
> > +		break;
> > +	case 2:
> > +		*val = get_unaligned_be16(buf);
> > +		break;
> > +	case 3:
> > +		*val = get_unaligned_be24(buf);
> > +		break;
> > +	case 4:
> > +		*val = get_unaligned_be32(buf);
> > +		break;
> > +	case 8:
> > +		*val = get_unaligned_be64(buf);
> > +		break;
> > +	default:
> > +		dev_err(regmap_get_device(map), "Error invalid reg-width %d for reg 0x%04x\n",

This should use %u with an unsigned len. Same below.

> > +			len, reg);
> > +		ret = -EINVAL;
> > +		break;
> > +	}
> > +
> > +out:
> > +	if (ret && err)
> > +		*err = ret;
> > +
> > +	return ret;
> > +}
> > +EXPORT_SYMBOL_GPL(cci_read);
> > +
> > +int cci_write(struct regmap *map, u32 reg, u64 val, int *err)
> > +{
> > +	int len, ret;
> 
> Same here.
> 
> > +	u8 buf[8];
> > +
> > +	if (err && *err)
> > +		return *err;
> > +
> > +	len = FIELD_GET(CCI_REG_WIDTH_MASK, reg);
> > +	reg = FIELD_GET(CCI_REG_ADDR_MASK, reg);
> > +
> > +	switch (len) {
> > +	case 1:
> > +		buf[0] = val;
> > +		break;
> > +	case 2:
> > +		put_unaligned_be16(val, buf);
> > +		break;
> > +	case 3:
> > +		put_unaligned_be24(val, buf);
> > +		break;
> > +	case 4:
> > +		put_unaligned_be32(val, buf);
> > +		break;
> > +	case 8:
> > +		put_unaligned_be64(val, buf);
> > +		break;
> > +	default:
> > +		dev_err(regmap_get_device(map), "Error invalid reg-width %d for reg 0x%04x\n",
> > +			len, reg);
> > +		ret = -EINVAL;
> > +		goto out;
> > +	}
> > +
> > +	ret = regmap_bulk_write(map, reg, buf, len);
> > +	if (ret)
> > +		dev_err(regmap_get_device(map), "Error writing reg 0x%4x: %d\n", reg, ret);
> > +
> > +out:
> > +	if (ret && err)
> > +		*err = ret;
> > +
> > +	return ret;
> > +}
> > +EXPORT_SYMBOL_GPL(cci_write);
> > +
> > +int cci_update_bits(struct regmap *map, u32 reg, u64 mask, u64 val, int *err)
> > +{
> > +	u64 readval;
> > +	int ret;
> > +
> > +	ret = cci_read(map, reg, &readval, err);
> > +	if (ret)
> > +		return ret;
> > +
> > +	val = (readval & ~mask) | (val & mask);
> > +
> > +	return cci_write(map, reg, val, err);
> > +}
> > +EXPORT_SYMBOL_GPL(cci_update_bits);
> > +
> > +int cci_multi_reg_write(struct regmap *map, const struct cci_reg_sequence *regs,
> > +			int num_regs, int *err)
> > +{
> > +	int i, ret;
> 
> unsigned int i?
> 
> Same for num_regs.
> 
> > +
> > +	for (i = 0; i < num_regs; i++) {
> > +		ret = cci_write(map, regs[i].reg, regs[i].val, err);
> > +		if (ret)
> > +			return ret;
> > +	}
> > +
> > +	return 0;
> > +}
> > +EXPORT_SYMBOL_GPL(cci_multi_reg_write);
> > +
> > +struct regmap *cci_regmap_init_i2c(struct i2c_client *client, int reg_addr_bits)

Should this be called devm_cci_regmap_init_i2c() ?

> > +{
> > +	struct regmap_config config = {
> > +		.reg_bits = reg_addr_bits,
> > +		.val_bits = 8,
> > +		.reg_format_endian = REGMAP_ENDIAN_BIG,
> > +		.disable_locking = true,
> > +	};
> > +
> > +	return devm_regmap_init_i2c(client, &config);
> > +}
> > +EXPORT_SYMBOL_GPL(cci_regmap_init_i2c);
> > +
> > +MODULE_LICENSE("GPL");
> > +MODULE_AUTHOR("Hans de Goede <hansg@kernel.org>");
> > diff --git a/include/media/v4l2-cci.h b/include/media/v4l2-cci.h
> > new file mode 100644
> > index 000000000000..5d8fdff086db
> > --- /dev/null
> > +++ b/include/media/v4l2-cci.h
> > @@ -0,0 +1,121 @@
> > +/* SPDX-License-Identifier: GPL-2.0 */
> > +/*
> > + * MIPI Camera Control Interface (CCI) register access helpers.
> > + *
> > + * Copyright (C) 2023 Hans de Goede <hansg@kernel.org>
> > + */
> > +#ifndef _V4L2_CCI_H
> > +#define _V4L2_CCI_H
> > +
> > +#include <linux/types.h>
> > +
> > +struct i2c_client;
> > +struct reg_sequence;

Not needed anymore.

> > +struct regmap;
> > +
> > +/**
> > + * struct cci_reg_sequence - An individual write from a sequence of CCI writes
> > + *
> > + * @reg: Register address, use CCI_REG#() macros to encode reg width
> > + * @val: Register value
> > + *
> > + * Register/value pairs for sequences of writes.
> > + */
> > +struct cci_reg_sequence {
> > +	u32 reg;
> > +	u64 val;
> > +};
> > +
> > +/*
> > + * Macros to define register address with the register width encoded
> > + * into the higher bits.
> > + */
> > +#define CCI_REG_ADDR_MASK		GENMASK(15, 0)
> > +#define CCI_REG_WIDTH_SHIFT		16
> > +#define CCI_REG_WIDTH_MASK		GENMASK(19, 16)
> > +
> > +#define CCI_REG8(x)			((1 << CCI_REG_WIDTH_SHIFT) | (x))
> > +#define CCI_REG16(x)			((2 << CCI_REG_WIDTH_SHIFT) | (x))
> > +#define CCI_REG24(x)			((3 << CCI_REG_WIDTH_SHIFT) | (x))
> > +#define CCI_REG32(x)			((4 << CCI_REG_WIDTH_SHIFT) | (x))
> > +#define CCI_REG64(x)			((8 << CCI_REG_WIDTH_SHIFT) | (x))
> > +
> > +/**
> > + * cci_read() - Read a value from a single CCI register
> > + *
> > + * @map: Register map to read from
> > + * @reg: Register address to read, use CCI_REG#() macros to encode reg width
> > + * @val: Pointer to store read value
> > + * @err: optional pointer to store errors, if a previous error is set

Nitpicking, s/optional/Optional/ to match the other arguments. Same
below.

> > + *       then the read will be skipped
> > + *
> > + * Return: %0 on success or a negative error code on failure.
> > + */
> > +int cci_read(struct regmap *map, u32 reg, u64 *val, int *err);
> > +
> > +/**
> > + * cci_write() - Write a value to a single CCI register
> > + *
> > + * @map: Register map to write to
> > + * @reg: Register address to write, use CCI_REG#() macros to encode reg width
> > + * @val: Value to be written
> > + * @err: optional pointer to store errors, if a previous error is set
> > + *       then the write will be skipped
> > + *
> > + * Return: %0 on success or a negative error code on failure.
> > + */
> > +int cci_write(struct regmap *map, u32 reg, u64 val, int *err);
> > +
> > +/**
> > + * cci_update_bits() - Perform a read/modify/write cycle on a single CCI register
> > + *
> > + * @map: Register map to update
> > + * @reg: Register address to update, use CCI_REG#() macros to encode reg width
> > + * @mask: Bitmask to change
> > + * @val: New value for bitmask
> > + * @err: optional pointer to store errors, if a previous error is set
> > + *       then the update will be skipped
> > + *
> > + * Note this uses read-modify-write to update the bits, atomicity wrt other

s/wrt/with regard to/

> > + * cci_*() register access functions is NOT guaranteed.
> > + *
> > + * Return: %0 on success or a negative error code on failure.
> > + */
> > +int cci_update_bits(struct regmap *map, u32 reg, u64 mask, u64 val, int *err);
> > +
> > +/**
> > + * cci_multi_reg_write() - Write multiple registers to the device
> > + *
> > + * @map: Register map to write to
> > + * @regs: Array of structures containing register-address, value pairs to be written
> > + *        register-addresses use CCI_REG#() macros to encode reg width
> > + * @num_regs: Number of registers to write
> > + * @err: optional pointer to store errors, if a previous error is set
> > + *       then the write will be skipped
> > + *
> > + * Write multiple registers to the device where the set of register, value
> > + * pairs are supplied in any order, possibly not all in a single range.
> > + *
> > + * Use of the CCI_REG#() macros to encode reg width is mandatory.
> > + *
> > + * For raw lists of register-address, -value pairs with only 8 bit
> > + * wide writes regmap_multi_reg_write() can be used instead.
> > + *
> > + * Return: %0 on success or a negative error code on failure.
> > + */
> > +int cci_multi_reg_write(struct regmap *map, const struct cci_reg_sequence *regs,
> > +			int num_regs, int *err);
> > +
> > +/**
> > + * cci_regmap_init_i2c() - Create regmap to use with cci_*() register access functions
> > + *
> > + * @client: i2c_client to create the regmap for
> > + * @reg_addr_bits: register address width to use (8 or 16)
> > + *
> > + * Note the memory for the created regmap is devm() managed, tied to the client.
> > + *
> > + * Return: %0 on success or a negative error code on failure.
> > + */
> > +struct regmap *cci_regmap_init_i2c(struct i2c_client *client, int reg_addr_bits);
> > +
> > +#endif
> 
> Could you run
> 
> 	./scripts/checkpatch.pl --strict --max-line-length=80
> 
> on this?
Sakari Ailus June 14, 2023, 9:48 p.m. UTC | #4
Hi Laurent,

On Thu, Jun 15, 2023 at 12:34:29AM +0300, Laurent Pinchart wrote:
> Hello,
> 
> On Wed, Jun 14, 2023 at 08:39:56PM +0000, Sakari Ailus wrote:
> > On Wed, Jun 14, 2023 at 09:23:39PM +0200, Hans de Goede wrote:
> > > The CSI2 specification specifies a standard method to access camera sensor
> > > registers called "Camera Control Interface (CCI)".
> > > 
> > > This uses either 8 or 16 bit (big-endian wire order) register addresses
> > > and supports 8, 16, 24 or 32 bit (big-endian wire order) register widths.
> > > 
> > > Currently a lot of Linux camera sensor drivers all have their own custom
> > > helpers for this, often copy and pasted from other drivers.
> > > 
> > > Add a set of generic helpers for this so that all sensor drivers can
> > > switch to a single common implementation.
> > > 
> > > These helpers take an extra optional "int *err" function parameter,
> > > this can be used to chain a bunch of register accesses together with
> > > only a single error check at the end, rather then needing to error
> > > check each individual register access. The first failing call will
> > > set the contents of err to a non 0 value and all other calls will
> > > then become no-ops.
> > > 
> > > Link: https://lore.kernel.org/linux-media/59aefa7f-7bf9-6736-6040-39551329cd0a@redhat.com/
> > > Signed-off-by: Hans de Goede <hdegoede@redhat.com>
> > > ---
> > > Changes in v2:
> > > - Drop cci_reg_type enum
> > > - Make having an encoded reg-width mandatory rather then using 0 to encode
> > >   8 bit width making reg-addresses without an encoded width default to
> > >   a width of 8
> > > - Add support for 64 bit wide registers
> 
> I'm in two minds about this. This means that the read and write
> functions take a u64 argument, which will be less efficient on 32-bit
> platforms. I think it would be possible, with some macro magic, to
> accept different argument sizes, but maybe that's a micro-optimization
> that would actually result in worse code. 
> 
> 64-bit support could be useful, but as far as I can tell, it's not used
> in this series, so maybe we could leave this for later ?

I prefer to have it now, I just told Tommaso working on the Alvium driver
to use this, and he needs 64-bit access. :-)

You could also easily have 32-bit and 64-bit variant of the functions, with
C11 _Generic(). Introducing it now would be easier than later.

> 
> > > - Introduce a new cci_reg_sequence struct with 64 bit reg values for 64 bit
> > >   support and without the delay_us field
> 
> This consumes extra memory too. Is it an issue ?

Most of the registers are 8-bit, 64-bit ones are exceedingly rare and will
probably remain so for CCI (small register space and slow bus!). Maybe the
64-bit support could be separate from the rest, using C11 _Generic() as
suggested above?
Laurent Pinchart June 14, 2023, 10:11 p.m. UTC | #5
Hello,

On Wed, Jun 14, 2023 at 09:48:00PM +0000, Sakari Ailus wrote:
> On Thu, Jun 15, 2023 at 12:34:29AM +0300, Laurent Pinchart wrote:
> > On Wed, Jun 14, 2023 at 08:39:56PM +0000, Sakari Ailus wrote:
> > > On Wed, Jun 14, 2023 at 09:23:39PM +0200, Hans de Goede wrote:
> > > > The CSI2 specification specifies a standard method to access camera sensor
> > > > registers called "Camera Control Interface (CCI)".
> > > > 
> > > > This uses either 8 or 16 bit (big-endian wire order) register addresses
> > > > and supports 8, 16, 24 or 32 bit (big-endian wire order) register widths.
> > > > 
> > > > Currently a lot of Linux camera sensor drivers all have their own custom
> > > > helpers for this, often copy and pasted from other drivers.
> > > > 
> > > > Add a set of generic helpers for this so that all sensor drivers can
> > > > switch to a single common implementation.
> > > > 
> > > > These helpers take an extra optional "int *err" function parameter,
> > > > this can be used to chain a bunch of register accesses together with
> > > > only a single error check at the end, rather then needing to error
> > > > check each individual register access. The first failing call will
> > > > set the contents of err to a non 0 value and all other calls will
> > > > then become no-ops.
> > > > 
> > > > Link: https://lore.kernel.org/linux-media/59aefa7f-7bf9-6736-6040-39551329cd0a@redhat.com/
> > > > Signed-off-by: Hans de Goede <hdegoede@redhat.com>
> > > > ---
> > > > Changes in v2:
> > > > - Drop cci_reg_type enum
> > > > - Make having an encoded reg-width mandatory rather then using 0 to encode
> > > >   8 bit width making reg-addresses without an encoded width default to
> > > >   a width of 8
> > > > - Add support for 64 bit wide registers
> > 
> > I'm in two minds about this. This means that the read and write
> > functions take a u64 argument, which will be less efficient on 32-bit
> > platforms. I think it would be possible, with some macro magic, to
> > accept different argument sizes, but maybe that's a micro-optimization
> > that would actually result in worse code. 
> > 
> > 64-bit support could be useful, but as far as I can tell, it's not used
> > in this series, so maybe we could leave this for later ?
> 
> I prefer to have it now, I just told Tommaso working on the Alvium driver
> to use this, and he needs 64-bit access. :-)
> 
> You could also easily have 32-bit and 64-bit variant of the functions, with
> C11 _Generic(). Introducing it now would be easier than later.
> 
> > 
> > > > - Introduce a new cci_reg_sequence struct with 64 bit reg values for 64 bit
> > > >   support and without the delay_us field
> > 
> > This consumes extra memory too. Is it an issue ?
> 
> Most of the registers are 8-bit, 64-bit ones are exceedingly rare and will
> probably remain so for CCI (small register space and slow bus!). Maybe the
> 64-bit support could be separate from the rest, using C11 _Generic() as
> suggested above?

For the read and write functions, that's an interesting idea, but I'm
not sure if it will be a useful optimization. I suppose we could try and
see.

For register sequences, I think it would become cumbersome and error
prone to have to call different functions because a 64-bit register is
present in the list. I wonder if we could somehow pack the array
instead, turning the array of cci_reg_sequence into a u8 array, with
32-bit register addresses followed by a number of bytes corresponding to
the register width. It should be doable with macros I think.

I'm not asking for this to be implemented right now, but I agree that
it's likely best to do so earlier than later.
Andy Shevchenko June 14, 2023, 10:21 p.m. UTC | #6
On Wed, Jun 14, 2023 at 11:49 PM Sakari Ailus
<sakari.ailus@linux.intel.com> wrote:
> On Wed, Jun 14, 2023 at 09:23:39PM +0200, Hans de Goede wrote:

...

> > +config V4L2_CCI
> > +     tristate
> > +     depends on I2C
>
> This won't do anything if the dependent driver will select V4L2_CCI, will
> it?

Actually it will. It may warn the user about missing dependency on the
`make *config` stage.
See, for example, this:
https://lore.kernel.org/lkml/1f6c4559-ee48-ca67-8ff1-f7f9d330bc12@suse.de/.

> I'd let the sensor driver depend on I2C instead. CCI is also supported
> on I3C, for instance.

> > +     select REGMAP_I2C
>
> This is a good question.
>
> How about adding V4L2_CCI_I2C that would select REGMAP_I2C?
Andy Shevchenko June 14, 2023, 10:24 p.m. UTC | #7
On Thu, Jun 15, 2023 at 1:21 AM Andy Shevchenko
<andy.shevchenko@gmail.com> wrote:
> On Wed, Jun 14, 2023 at 11:49 PM Sakari Ailus
> <sakari.ailus@linux.intel.com> wrote:
> > On Wed, Jun 14, 2023 at 09:23:39PM +0200, Hans de Goede wrote:

...

> > > +config V4L2_CCI
> > > +     tristate
> > > +     depends on I2C
> >
> > This won't do anything if the dependent driver will select V4L2_CCI, will
> > it?
>
> Actually it will. It may warn the user about missing dependency on the
> `make *config` stage.
> See, for example, this:
> https://lore.kernel.org/lkml/1f6c4559-ee48-ca67-8ff1-f7f9d330bc12@suse.de/.

With corrected link
https://lore.kernel.org/lkml/20220316183708.1505846-1-arnd@kernel.org/

> > I'd let the sensor driver depend on I2C instead. CCI is also supported
> > on I3C, for instance.
Hans de Goede June 15, 2023, 8:45 a.m. UTC | #8
Hi Sakari,

On 6/14/23 22:39, Sakari Ailus wrote:
> Hi Hans,
> 
> Thank you for the update.
> 
> On Wed, Jun 14, 2023 at 09:23:39PM +0200, Hans de Goede wrote:
>> The CSI2 specification specifies a standard method to access camera sensor
>> registers called "Camera Control Interface (CCI)".
>>
>> This uses either 8 or 16 bit (big-endian wire order) register addresses
>> and supports 8, 16, 24 or 32 bit (big-endian wire order) register widths.
>>
>> Currently a lot of Linux camera sensor drivers all have their own custom
>> helpers for this, often copy and pasted from other drivers.
>>
>> Add a set of generic helpers for this so that all sensor drivers can
>> switch to a single common implementation.
>>
>> These helpers take an extra optional "int *err" function parameter,
>> this can be used to chain a bunch of register accesses together with
>> only a single error check at the end, rather then needing to error
>> check each individual register access. The first failing call will
>> set the contents of err to a non 0 value and all other calls will
>> then become no-ops.
>>
>> Link: https://lore.kernel.org/linux-media/59aefa7f-7bf9-6736-6040-39551329cd0a@redhat.com/
>> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
>> ---
>> Changes in v2:
>> - Drop cci_reg_type enum
>> - Make having an encoded reg-width mandatory rather then using 0 to encode
>>   8 bit width making reg-addresses without an encoded width default to
>>   a width of 8
>> - Add support for 64 bit wide registers
>> - Introduce a new cci_reg_sequence struct with 64 bit reg values for 64 bit
>>   support and without the delay_us field
>> - Various kerneldoc updates
>> - Stop supporting delays in cci_multi_reg_write()
>> - Some includes cleanups
>> - Disable regmap locking
>> ---
>>  Documentation/driver-api/media/v4l2-cci.rst  |   5 +
>>  Documentation/driver-api/media/v4l2-core.rst |   1 +
>>  drivers/media/v4l2-core/Kconfig              |   5 +
>>  drivers/media/v4l2-core/Makefile             |   1 +
>>  drivers/media/v4l2-core/v4l2-cci.c           | 157 +++++++++++++++++++
>>  include/media/v4l2-cci.h                     | 121 ++++++++++++++
>>  6 files changed, 290 insertions(+)
>>  create mode 100644 Documentation/driver-api/media/v4l2-cci.rst
>>  create mode 100644 drivers/media/v4l2-core/v4l2-cci.c
>>  create mode 100644 include/media/v4l2-cci.h
>>
>> diff --git a/Documentation/driver-api/media/v4l2-cci.rst b/Documentation/driver-api/media/v4l2-cci.rst
>> new file mode 100644
>> index 000000000000..dd297a40ed20
>> --- /dev/null
>> +++ b/Documentation/driver-api/media/v4l2-cci.rst
>> @@ -0,0 +1,5 @@
>> +.. SPDX-License-Identifier: GPL-2.0
>> +
>> +V4L2 CCI kAPI
>> +^^^^^^^^^^^^^
>> +.. kernel-doc:: include/media/v4l2-cci.h
>> diff --git a/Documentation/driver-api/media/v4l2-core.rst b/Documentation/driver-api/media/v4l2-core.rst
>> index 1a8c4a5f256b..239045ecc8f4 100644
>> --- a/Documentation/driver-api/media/v4l2-core.rst
>> +++ b/Documentation/driver-api/media/v4l2-core.rst
>> @@ -22,6 +22,7 @@ Video4Linux devices
>>      v4l2-mem2mem
>>      v4l2-async
>>      v4l2-fwnode
>> +    v4l2-cci
>>      v4l2-rect
>>      v4l2-tuner
>>      v4l2-common
>> diff --git a/drivers/media/v4l2-core/Kconfig b/drivers/media/v4l2-core/Kconfig
>> index 348559bc2468..523ba243261d 100644
>> --- a/drivers/media/v4l2-core/Kconfig
>> +++ b/drivers/media/v4l2-core/Kconfig
>> @@ -74,6 +74,11 @@ config V4L2_FWNODE
>>  config V4L2_ASYNC
>>  	tristate
>>  
>> +config V4L2_CCI
>> +	tristate
>> +	depends on I2C
> 
> This won't do anything if the dependent driver will select V4L2_CCI, will
> it? I'd let the sensor driver depend on I2C instead. CCI is also supported
> on I3C, for instance.

It will cause a Kconfig error if the dependent driver does not depend
on I2C. Kconfig items doing select MUST depend on all the depends on
of the items they are selecting; and (continued below)

> 
>> +	select REGMAP_I2C
> 
> This is a good question.
> 
> How about adding V4L2_CCI_I2C that would select REGMAP_I2C?

v4l2-cci.ko uses the devm_regmap_init_i2c() symbol, so
REGMAP_I2C must be enabled when V4L2_CCI is enabled and
REGMAP_I2C is a symbol which should be selected rather
then depended on when necessary.

> 
>> +
>>  # Used by drivers that need Videobuf modules
>>  config VIDEOBUF_GEN
>>  	tristate
>> diff --git a/drivers/media/v4l2-core/Makefile b/drivers/media/v4l2-core/Makefile
>> index 41d91bd10cf2..be2551705755 100644
>> --- a/drivers/media/v4l2-core/Makefile
>> +++ b/drivers/media/v4l2-core/Makefile
>> @@ -25,6 +25,7 @@ videodev-$(CONFIG_VIDEO_V4L2_I2C) += v4l2-i2c.o
>>  # (e. g. LC_ALL=C sort Makefile)
>>  
>>  obj-$(CONFIG_V4L2_ASYNC) += v4l2-async.o
>> +obj-$(CONFIG_V4L2_CCI) += v4l2-cci.o
>>  obj-$(CONFIG_V4L2_FLASH_LED_CLASS) += v4l2-flash-led-class.o
>>  obj-$(CONFIG_V4L2_FWNODE) += v4l2-fwnode.o
>>  obj-$(CONFIG_V4L2_H264) += v4l2-h264.o
>> diff --git a/drivers/media/v4l2-core/v4l2-cci.c b/drivers/media/v4l2-core/v4l2-cci.c
>> new file mode 100644
>> index 000000000000..94764f3ebc6c
>> --- /dev/null
>> +++ b/drivers/media/v4l2-core/v4l2-cci.c
>> @@ -0,0 +1,157 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * MIPI Camera Control Interface (CCI) register access helpers.
>> + *
>> + * Copyright (C) 2023 Hans de Goede <hansg@kernel.org>
>> + */
>> +
>> +#include <linux/bitfield.h>
>> +#include <linux/delay.h>
>> +#include <linux/dev_printk.h>
>> +#include <linux/module.h>
>> +#include <linux/regmap.h>
>> +#include <linux/types.h>
>> +
>> +#include <asm/unaligned.h>
>> +
>> +#include <media/v4l2-cci.h>
>> +
>> +int cci_read(struct regmap *map, u32 reg, u64 *val, int *err)
>> +{
>> +	int len, ret;
> 
> len would look better unsigned.

Ok, I'll fix this for v3 and the same for the other unsigned
remarks.


>> +	u8 buf[8];
>> +
>> +	if (err && *err)
>> +		return *err;
>> +
>> +	len = FIELD_GET(CCI_REG_WIDTH_MASK, reg);
>> +	reg = FIELD_GET(CCI_REG_ADDR_MASK, reg);
>> +
>> +	ret = regmap_bulk_read(map, reg, buf, len);
>> +	if (ret) {
>> +		dev_err(regmap_get_device(map), "Error reading reg 0x%4x: %d\n", reg, ret);
>> +		goto out;
>> +	}
>> +
>> +	switch (len) {
>> +	case 1:
>> +		*val = buf[0];
>> +		break;
>> +	case 2:
>> +		*val = get_unaligned_be16(buf);
>> +		break;
>> +	case 3:
>> +		*val = get_unaligned_be24(buf);
>> +		break;
>> +	case 4:
>> +		*val = get_unaligned_be32(buf);
>> +		break;
>> +	case 8:
>> +		*val = get_unaligned_be64(buf);
>> +		break;
>> +	default:
>> +		dev_err(regmap_get_device(map), "Error invalid reg-width %d for reg 0x%04x\n",
>> +			len, reg);
>> +		ret = -EINVAL;
>> +		break;
>> +	}
>> +
>> +out:
>> +	if (ret && err)
>> +		*err = ret;
>> +
>> +	return ret;
>> +}
>> +EXPORT_SYMBOL_GPL(cci_read);
>> +
>> +int cci_write(struct regmap *map, u32 reg, u64 val, int *err)
>> +{
>> +	int len, ret;
> 
> Same here.
> 
>> +	u8 buf[8];
>> +
>> +	if (err && *err)
>> +		return *err;
>> +
>> +	len = FIELD_GET(CCI_REG_WIDTH_MASK, reg);
>> +	reg = FIELD_GET(CCI_REG_ADDR_MASK, reg);
>> +
>> +	switch (len) {
>> +	case 1:
>> +		buf[0] = val;
>> +		break;
>> +	case 2:
>> +		put_unaligned_be16(val, buf);
>> +		break;
>> +	case 3:
>> +		put_unaligned_be24(val, buf);
>> +		break;
>> +	case 4:
>> +		put_unaligned_be32(val, buf);
>> +		break;
>> +	case 8:
>> +		put_unaligned_be64(val, buf);
>> +		break;
>> +	default:
>> +		dev_err(regmap_get_device(map), "Error invalid reg-width %d for reg 0x%04x\n",
>> +			len, reg);
>> +		ret = -EINVAL;
>> +		goto out;
>> +	}
>> +
>> +	ret = regmap_bulk_write(map, reg, buf, len);
>> +	if (ret)
>> +		dev_err(regmap_get_device(map), "Error writing reg 0x%4x: %d\n", reg, ret);
>> +
>> +out:
>> +	if (ret && err)
>> +		*err = ret;
>> +
>> +	return ret;
>> +}
>> +EXPORT_SYMBOL_GPL(cci_write);
>> +
>> +int cci_update_bits(struct regmap *map, u32 reg, u64 mask, u64 val, int *err)
>> +{
>> +	u64 readval;
>> +	int ret;
>> +
>> +	ret = cci_read(map, reg, &readval, err);
>> +	if (ret)
>> +		return ret;
>> +
>> +	val = (readval & ~mask) | (val & mask);
>> +
>> +	return cci_write(map, reg, val, err);
>> +}
>> +EXPORT_SYMBOL_GPL(cci_update_bits);
>> +
>> +int cci_multi_reg_write(struct regmap *map, const struct cci_reg_sequence *regs,
>> +			int num_regs, int *err)
>> +{
>> +	int i, ret;
> 
> unsigned int i?
> 
> Same for num_regs.
> 
>> +
>> +	for (i = 0; i < num_regs; i++) {
>> +		ret = cci_write(map, regs[i].reg, regs[i].val, err);
>> +		if (ret)
>> +			return ret;
>> +	}
>> +
>> +	return 0;
>> +}
>> +EXPORT_SYMBOL_GPL(cci_multi_reg_write);
>> +
>> +struct regmap *cci_regmap_init_i2c(struct i2c_client *client, int reg_addr_bits)
>> +{
>> +	struct regmap_config config = {
>> +		.reg_bits = reg_addr_bits,
>> +		.val_bits = 8,
>> +		.reg_format_endian = REGMAP_ENDIAN_BIG,
>> +		.disable_locking = true,
>> +	};
>> +
>> +	return devm_regmap_init_i2c(client, &config);
>> +}
>> +EXPORT_SYMBOL_GPL(cci_regmap_init_i2c);
>> +
>> +MODULE_LICENSE("GPL");
>> +MODULE_AUTHOR("Hans de Goede <hansg@kernel.org>");
>> diff --git a/include/media/v4l2-cci.h b/include/media/v4l2-cci.h
>> new file mode 100644
>> index 000000000000..5d8fdff086db
>> --- /dev/null
>> +++ b/include/media/v4l2-cci.h
>> @@ -0,0 +1,121 @@
>> +/* SPDX-License-Identifier: GPL-2.0 */
>> +/*
>> + * MIPI Camera Control Interface (CCI) register access helpers.
>> + *
>> + * Copyright (C) 2023 Hans de Goede <hansg@kernel.org>
>> + */
>> +#ifndef _V4L2_CCI_H
>> +#define _V4L2_CCI_H
>> +
>> +#include <linux/types.h>
>> +
>> +struct i2c_client;
>> +struct reg_sequence;
>> +struct regmap;
>> +
>> +/**
>> + * struct cci_reg_sequence - An individual write from a sequence of CCI writes
>> + *
>> + * @reg: Register address, use CCI_REG#() macros to encode reg width
>> + * @val: Register value
>> + *
>> + * Register/value pairs for sequences of writes.
>> + */
>> +struct cci_reg_sequence {
>> +	u32 reg;
>> +	u64 val;
>> +};
>> +
>> +/*
>> + * Macros to define register address with the register width encoded
>> + * into the higher bits.
>> + */
>> +#define CCI_REG_ADDR_MASK		GENMASK(15, 0)
>> +#define CCI_REG_WIDTH_SHIFT		16
>> +#define CCI_REG_WIDTH_MASK		GENMASK(19, 16)
>> +
>> +#define CCI_REG8(x)			((1 << CCI_REG_WIDTH_SHIFT) | (x))
>> +#define CCI_REG16(x)			((2 << CCI_REG_WIDTH_SHIFT) | (x))
>> +#define CCI_REG24(x)			((3 << CCI_REG_WIDTH_SHIFT) | (x))
>> +#define CCI_REG32(x)			((4 << CCI_REG_WIDTH_SHIFT) | (x))
>> +#define CCI_REG64(x)			((8 << CCI_REG_WIDTH_SHIFT) | (x))
>> +
>> +/**
>> + * cci_read() - Read a value from a single CCI register
>> + *
>> + * @map: Register map to read from
>> + * @reg: Register address to read, use CCI_REG#() macros to encode reg width
>> + * @val: Pointer to store read value
>> + * @err: optional pointer to store errors, if a previous error is set
>> + *       then the read will be skipped
>> + *
>> + * Return: %0 on success or a negative error code on failure.
>> + */
>> +int cci_read(struct regmap *map, u32 reg, u64 *val, int *err);
>> +
>> +/**
>> + * cci_write() - Write a value to a single CCI register
>> + *
>> + * @map: Register map to write to
>> + * @reg: Register address to write, use CCI_REG#() macros to encode reg width
>> + * @val: Value to be written
>> + * @err: optional pointer to store errors, if a previous error is set
>> + *       then the write will be skipped
>> + *
>> + * Return: %0 on success or a negative error code on failure.
>> + */
>> +int cci_write(struct regmap *map, u32 reg, u64 val, int *err);
>> +
>> +/**
>> + * cci_update_bits() - Perform a read/modify/write cycle on a single CCI register
>> + *
>> + * @map: Register map to update
>> + * @reg: Register address to update, use CCI_REG#() macros to encode reg width
>> + * @mask: Bitmask to change
>> + * @val: New value for bitmask
>> + * @err: optional pointer to store errors, if a previous error is set
>> + *       then the update will be skipped
>> + *
>> + * Note this uses read-modify-write to update the bits, atomicity wrt other
>> + * cci_*() register access functions is NOT guaranteed.
>> + *
>> + * Return: %0 on success or a negative error code on failure.
>> + */
>> +int cci_update_bits(struct regmap *map, u32 reg, u64 mask, u64 val, int *err);
>> +
>> +/**
>> + * cci_multi_reg_write() - Write multiple registers to the device
>> + *
>> + * @map: Register map to write to
>> + * @regs: Array of structures containing register-address, value pairs to be written
>> + *        register-addresses use CCI_REG#() macros to encode reg width
>> + * @num_regs: Number of registers to write
>> + * @err: optional pointer to store errors, if a previous error is set
>> + *       then the write will be skipped
>> + *
>> + * Write multiple registers to the device where the set of register, value
>> + * pairs are supplied in any order, possibly not all in a single range.
>> + *
>> + * Use of the CCI_REG#() macros to encode reg width is mandatory.
>> + *
>> + * For raw lists of register-address, -value pairs with only 8 bit
>> + * wide writes regmap_multi_reg_write() can be used instead.
>> + *
>> + * Return: %0 on success or a negative error code on failure.
>> + */
>> +int cci_multi_reg_write(struct regmap *map, const struct cci_reg_sequence *regs,
>> +			int num_regs, int *err);
>> +
>> +/**
>> + * cci_regmap_init_i2c() - Create regmap to use with cci_*() register access functions
>> + *
>> + * @client: i2c_client to create the regmap for
>> + * @reg_addr_bits: register address width to use (8 or 16)
>> + *
>> + * Note the memory for the created regmap is devm() managed, tied to the client.
>> + *
>> + * Return: %0 on success or a negative error code on failure.
>> + */
>> +struct regmap *cci_regmap_init_i2c(struct i2c_client *client, int reg_addr_bits);
>> +
>> +#endif
> 
> Could you run
> 
> 	./scripts/checkpatch.pl --strict --max-line-length=80
> 
> on this?

As I mentioned during the v1 review where you also asked about
the 80 column limit, can we first please have an official
decision what the column limit is for drivers/media and then
also document this somewhere?

Also note that you are asking me to modify the checkpatch
default max-line-length here. So basically you are deviating
from the official kernel coding style standards here.

You are asking for 80 columns. Andy often adds review remarks
along the lines of:

"this can fit on a single line" assuming the now official 100
chars hard limit.

And I cannot make both you and Andy happy at the same time.
So please pick a limit, *document it* and then stick with it.

This current inconsistency between reviewers is unhelpful.

My personal opinion on this is that sometimes going over
80 chars actually results in better readable code,
so I have a slight preference to just stick with the kernel
default of 100 chars. Sticking to the kernel default also
makes life a lot easier for people contributing to multiple
subsystems. So my vote goes to sticking with the new
kernel default of 100 chars.

I'm happy to adjust this patch-set to fit everything in
80 chars, but can we please first get some clarity on
what actual column limit we want for drivers/media ?

Regards,

Hans
Hans de Goede June 15, 2023, 8:56 a.m. UTC | #9
Hi,

On 6/14/23 23:34, Laurent Pinchart wrote:
> Hello,
> 
> On Wed, Jun 14, 2023 at 08:39:56PM +0000, Sakari Ailus wrote:
>> On Wed, Jun 14, 2023 at 09:23:39PM +0200, Hans de Goede wrote:
>>> The CSI2 specification specifies a standard method to access camera sensor
>>> registers called "Camera Control Interface (CCI)".
>>>
>>> This uses either 8 or 16 bit (big-endian wire order) register addresses
>>> and supports 8, 16, 24 or 32 bit (big-endian wire order) register widths.
>>>
>>> Currently a lot of Linux camera sensor drivers all have their own custom
>>> helpers for this, often copy and pasted from other drivers.
>>>
>>> Add a set of generic helpers for this so that all sensor drivers can
>>> switch to a single common implementation.
>>>
>>> These helpers take an extra optional "int *err" function parameter,
>>> this can be used to chain a bunch of register accesses together with
>>> only a single error check at the end, rather then needing to error
>>> check each individual register access. The first failing call will
>>> set the contents of err to a non 0 value and all other calls will
>>> then become no-ops.
>>>
>>> Link: https://lore.kernel.org/linux-media/59aefa7f-7bf9-6736-6040-39551329cd0a@redhat.com/
>>> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
>>> ---
>>> Changes in v2:
>>> - Drop cci_reg_type enum
>>> - Make having an encoded reg-width mandatory rather then using 0 to encode
>>>   8 bit width making reg-addresses without an encoded width default to
>>>   a width of 8
>>> - Add support for 64 bit wide registers
> 
> I'm in two minds about this. This means that the read and write
> functions take a u64 argument, which will be less efficient on 32-bit
> platforms. I think it would be possible, with some macro magic, to
> accept different argument sizes, but maybe that's a micro-optimization
> that would actually result in worse code. 
> 
> 64-bit support could be useful, but as far as I can tell, it's not used
> in this series, so maybe we could leave this for later ?

Besides Sakari mentioning a sensor driver being in the works
which needs this. Adding 64 bit support later is troublesome
because it will change the prototype of cci_read, specically
the return by reference val will change from u32 *val to
u64 *val, requiring changing all the callers.

So if anything now is the time to change this.

As for this being slower on 32 bit archs. We are talking about
code here which is ultimately transferring data over 400 KHz
i2c. The i2c is always going to be the bottleneck and if we
want / need to optimize this we really need to focus on
reducing unnecessary i2c transfers first.

>>> - Introduce a new cci_reg_sequence struct with 64 bit reg values for 64 bit
>>>   support and without the delay_us field
> 
> This consumes extra memory too. Is it an issue ?

Compared to v1 this does not consume extra memory since
this drops the delay_us field.

It does consume extra memory to still adding a new
cci_reg_sequence struct with 2 32 bit members. But
given that any hw using sensor drivers is going to
need to have multiple buffers to store the sensor
data with each buffer consuming megabytes of RAM
I'm not really worried about growing the size of
a couple of fixed register init lists by a bit.

As for your other minor review comments I agree and I'll
fix them all for the next version.

Regards,

Hans
Hans de Goede June 15, 2023, 9:11 a.m. UTC | #10
Hi Sakari,

On 6/14/23 23:48, Sakari Ailus wrote:
> Hi Laurent,
> 
> On Thu, Jun 15, 2023 at 12:34:29AM +0300, Laurent Pinchart wrote:
>> Hello,
>>
>> On Wed, Jun 14, 2023 at 08:39:56PM +0000, Sakari Ailus wrote:
>>> On Wed, Jun 14, 2023 at 09:23:39PM +0200, Hans de Goede wrote:
>>>> The CSI2 specification specifies a standard method to access camera sensor
>>>> registers called "Camera Control Interface (CCI)".
>>>>
>>>> This uses either 8 or 16 bit (big-endian wire order) register addresses
>>>> and supports 8, 16, 24 or 32 bit (big-endian wire order) register widths.
>>>>
>>>> Currently a lot of Linux camera sensor drivers all have their own custom
>>>> helpers for this, often copy and pasted from other drivers.
>>>>
>>>> Add a set of generic helpers for this so that all sensor drivers can
>>>> switch to a single common implementation.
>>>>
>>>> These helpers take an extra optional "int *err" function parameter,
>>>> this can be used to chain a bunch of register accesses together with
>>>> only a single error check at the end, rather then needing to error
>>>> check each individual register access. The first failing call will
>>>> set the contents of err to a non 0 value and all other calls will
>>>> then become no-ops.
>>>>
>>>> Link: https://lore.kernel.org/linux-media/59aefa7f-7bf9-6736-6040-39551329cd0a@redhat.com/
>>>> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
>>>> ---
>>>> Changes in v2:
>>>> - Drop cci_reg_type enum
>>>> - Make having an encoded reg-width mandatory rather then using 0 to encode
>>>>   8 bit width making reg-addresses without an encoded width default to
>>>>   a width of 8
>>>> - Add support for 64 bit wide registers
>>
>> I'm in two minds about this. This means that the read and write
>> functions take a u64 argument, which will be less efficient on 32-bit
>> platforms. I think it would be possible, with some macro magic, to
>> accept different argument sizes, but maybe that's a micro-optimization
>> that would actually result in worse code. 
>>
>> 64-bit support could be useful, but as far as I can tell, it's not used
>> in this series, so maybe we could leave this for later ?
> 
> I prefer to have it now, I just told Tommaso working on the Alvium driver
> to use this, and he needs 64-bit access. :-)
> 
> You could also easily have 32-bit and 64-bit variant of the functions, with
> C11 _Generic(). Introducing it now would be easier than later.

I took a quick look at C11 _Generic() and that looks at the type
of "things" so in this case it would look at type of the val argument.

Problem is that that can still be e.g. an int when doing a
read/write from a 64 bit registers.

So we would then need to handle the 64 bit width case in the 32
bit versions of the functions too.

And likewise I can see someone passing a long on a 64 bit
arch while doing a cci_write() to a non 64 bit register.

So this would basically mean copy and pasting cci_read()
+ cci_write() 2x with the only difference being one
variant taking a 32 bit val argument and the other a
64 bit val argument.

This seems like premature optimization to me.

As mentioned in my reply to Laurent if we want to
optimize things we really should look at avoiding
unnecessary i2c transfers, or packing multiple
writes into a single i2c transfer for writes to
subsequent registers. That is where significant
speedups can be made.

Regards,

Hans
Laurent Pinchart June 15, 2023, 9:21 a.m. UTC | #11
On Thu, Jun 15, 2023 at 11:11:20AM +0200, Hans de Goede wrote:
> Hi Sakari,
> 
> On 6/14/23 23:48, Sakari Ailus wrote:
> > Hi Laurent,
> > 
> > On Thu, Jun 15, 2023 at 12:34:29AM +0300, Laurent Pinchart wrote:
> >> Hello,
> >>
> >> On Wed, Jun 14, 2023 at 08:39:56PM +0000, Sakari Ailus wrote:
> >>> On Wed, Jun 14, 2023 at 09:23:39PM +0200, Hans de Goede wrote:
> >>>> The CSI2 specification specifies a standard method to access camera sensor
> >>>> registers called "Camera Control Interface (CCI)".
> >>>>
> >>>> This uses either 8 or 16 bit (big-endian wire order) register addresses
> >>>> and supports 8, 16, 24 or 32 bit (big-endian wire order) register widths.
> >>>>
> >>>> Currently a lot of Linux camera sensor drivers all have their own custom
> >>>> helpers for this, often copy and pasted from other drivers.
> >>>>
> >>>> Add a set of generic helpers for this so that all sensor drivers can
> >>>> switch to a single common implementation.
> >>>>
> >>>> These helpers take an extra optional "int *err" function parameter,
> >>>> this can be used to chain a bunch of register accesses together with
> >>>> only a single error check at the end, rather then needing to error
> >>>> check each individual register access. The first failing call will
> >>>> set the contents of err to a non 0 value and all other calls will
> >>>> then become no-ops.
> >>>>
> >>>> Link: https://lore.kernel.org/linux-media/59aefa7f-7bf9-6736-6040-39551329cd0a@redhat.com/
> >>>> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
> >>>> ---
> >>>> Changes in v2:
> >>>> - Drop cci_reg_type enum
> >>>> - Make having an encoded reg-width mandatory rather then using 0 to encode
> >>>>   8 bit width making reg-addresses without an encoded width default to
> >>>>   a width of 8
> >>>> - Add support for 64 bit wide registers
> >>
> >> I'm in two minds about this. This means that the read and write
> >> functions take a u64 argument, which will be less efficient on 32-bit
> >> platforms. I think it would be possible, with some macro magic, to
> >> accept different argument sizes, but maybe that's a micro-optimization
> >> that would actually result in worse code. 
> >>
> >> 64-bit support could be useful, but as far as I can tell, it's not used
> >> in this series, so maybe we could leave this for later ?
> > 
> > I prefer to have it now, I just told Tommaso working on the Alvium driver
> > to use this, and he needs 64-bit access. :-)
> > 
> > You could also easily have 32-bit and 64-bit variant of the functions, with
> > C11 _Generic(). Introducing it now would be easier than later.
> 
> I took a quick look at C11 _Generic() and that looks at the type
> of "things" so in this case it would look at type of the val argument.
> 
> Problem is that that can still be e.g. an int when doing a
> read/write from a 64 bit registers.
> 
> So we would then need to handle the 64 bit width case in the 32
> bit versions of the functions too.
> 
> And likewise I can see someone passing a long on a 64 bit
> arch while doing a cci_write() to a non 64 bit register.
> 
> So this would basically mean copy and pasting cci_read()
> + cci_write() 2x with the only difference being one
> variant taking a 32 bit val argument and the other a
> 64 bit val argument.
> 
> This seems like premature optimization to me.
> 
> As mentioned in my reply to Laurent if we want to
> optimize things we really should look at avoiding
> unnecessary i2c transfers, or packing multiple
> writes into a single i2c transfer for writes to
> subsequent registers. That is where significant
> speedups can be made.

This is something I'd really like to see, but it's way more work.

There's an important need of applying changes atomically, which is often
not possible to strictly guarantee over I2C. Userspace ends up writing
V4L2 controls as quickly as it can after the start of a frame, hoping
they will all reach the sensor before the end of the frame. Some
platforms have camera-specific I2C controllers that have the ability to
buffer I2C transfers and issue them based on a hardware trigger. How to
fit this in thé kernel I2C API will be an interesting exercise.
Sakari Ailus June 15, 2023, 9:54 a.m. UTC | #12
Hi Hans,

On Thu, Jun 15, 2023 at 10:45:35AM +0200, Hans de Goede wrote:
> Hi Sakari,
> 
> On 6/14/23 22:39, Sakari Ailus wrote:

...
> >> diff --git a/drivers/media/v4l2-core/Kconfig b/drivers/media/v4l2-core/Kconfig
> >> index 348559bc2468..523ba243261d 100644
> >> --- a/drivers/media/v4l2-core/Kconfig
> >> +++ b/drivers/media/v4l2-core/Kconfig
> >> @@ -74,6 +74,11 @@ config V4L2_FWNODE
> >>  config V4L2_ASYNC
> >>  	tristate
> >>  
> >> +config V4L2_CCI
> >> +	tristate
> >> +	depends on I2C
> > 
> > This won't do anything if the dependent driver will select V4L2_CCI, will
> > it? I'd let the sensor driver depend on I2C instead. CCI is also supported
> > on I3C, for instance.
> 
> It will cause a Kconfig error if the dependent driver does not depend
> on I2C. Kconfig items doing select MUST depend on all the depends on
> of the items they are selecting; and (continued below)

Maybe this has changed? It used to be that these cases were silently
ignored and it wasn't that long ago. I haven't been following this up.

Nevertheless, this shouldn't depend on I2C as such.

> 
> > 
> >> +	select REGMAP_I2C
> > 
> > This is a good question.
> > 
> > How about adding V4L2_CCI_I2C that would select REGMAP_I2C?
> 
> v4l2-cci.ko uses the devm_regmap_init_i2c() symbol, so
> REGMAP_I2C must be enabled when V4L2_CCI is enabled and
> REGMAP_I2C is a symbol which should be selected rather
> then depended on when necessary.

I agree.

...

> >> +/**
> >> + * cci_regmap_init_i2c() - Create regmap to use with cci_*() register access functions
> >> + *
> >> + * @client: i2c_client to create the regmap for
> >> + * @reg_addr_bits: register address width to use (8 or 16)
> >> + *
> >> + * Note the memory for the created regmap is devm() managed, tied to the client.
> >> + *
> >> + * Return: %0 on success or a negative error code on failure.
> >> + */
> >> +struct regmap *cci_regmap_init_i2c(struct i2c_client *client, int reg_addr_bits);
> >> +
> >> +#endif
> > 
> > Could you run
> > 
> > 	./scripts/checkpatch.pl --strict --max-line-length=80
> > 
> > on this?
> 
> As I mentioned during the v1 review where you also asked about
> the 80 column limit, can we first please have an official
> decision what the column limit is for drivers/media and then
> also document this somewhere?

This is documented in
Documentation/driver-api/media/maintainer-entry-profile.rst and media tree
follows that.

> 
> Also note that you are asking me to modify the checkpatch
> default max-line-length here. So basically you are deviating
> from the official kernel coding style standards here.

We're not. Note that checkpatch.pl is a tool to check code, it isn't the
coding style itself, which is documented in
Documentation/process/coding-style.rst . The default in checkpatch.pl was
changed as it often produced many warnings where there was a justified
reason for having longer lines (such as violating other rules in coding
style).

> 
> You are asking for 80 columns. Andy often adds review remarks
> along the lines of:
> 
> "this can fit on a single line" assuming the now official 100
> chars hard limit.

I know...

> 
> And I cannot make both you and Andy happy at the same time.
> So please pick a limit, *document it* and then stick with it.
> 
> This current inconsistency between reviewers is unhelpful.
> 
> My personal opinion on this is that sometimes going over
> 80 chars actually results in better readable code,
> so I have a slight preference to just stick with the kernel
> default of 100 chars. Sticking to the kernel default also
> makes life a lot easier for people contributing to multiple
> subsystems. So my vote goes to sticking with the new
> kernel default of 100 chars.
> 
> I'm happy to adjust this patch-set to fit everything in
> 80 chars, but can we please first get some clarity on
> what actual column limit we want for drivers/media ?

Answered above. Note that the limit is not strict but it appears that in
this set there are many longer lines than 80 but no apparent reason for
having them that way.
Tommaso Merciai June 15, 2023, 10:05 a.m. UTC | #13
Hi Hans, Laurent, Sakari,

Can I cherry-pick this patch and use these new functions also
for cci regs of the alvium driver? Are on going to be merge?

Let me know.
Thanks! :)

Regards,
Tommaso

On Thu, Jun 15, 2023 at 12:21:00PM +0300, Laurent Pinchart wrote:
> On Thu, Jun 15, 2023 at 11:11:20AM +0200, Hans de Goede wrote:
> > Hi Sakari,
> > 
> > On 6/14/23 23:48, Sakari Ailus wrote:
> > > Hi Laurent,
> > > 
> > > On Thu, Jun 15, 2023 at 12:34:29AM +0300, Laurent Pinchart wrote:
> > >> Hello,
> > >>
> > >> On Wed, Jun 14, 2023 at 08:39:56PM +0000, Sakari Ailus wrote:
> > >>> On Wed, Jun 14, 2023 at 09:23:39PM +0200, Hans de Goede wrote:
> > >>>> The CSI2 specification specifies a standard method to access camera sensor
> > >>>> registers called "Camera Control Interface (CCI)".
> > >>>>
> > >>>> This uses either 8 or 16 bit (big-endian wire order) register addresses
> > >>>> and supports 8, 16, 24 or 32 bit (big-endian wire order) register widths.
> > >>>>
> > >>>> Currently a lot of Linux camera sensor drivers all have their own custom
> > >>>> helpers for this, often copy and pasted from other drivers.
> > >>>>
> > >>>> Add a set of generic helpers for this so that all sensor drivers can
> > >>>> switch to a single common implementation.
> > >>>>
> > >>>> These helpers take an extra optional "int *err" function parameter,
> > >>>> this can be used to chain a bunch of register accesses together with
> > >>>> only a single error check at the end, rather then needing to error
> > >>>> check each individual register access. The first failing call will
> > >>>> set the contents of err to a non 0 value and all other calls will
> > >>>> then become no-ops.
> > >>>>
> > >>>> Link: https://lore.kernel.org/linux-media/59aefa7f-7bf9-6736-6040-39551329cd0a@redhat.com/
> > >>>> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
> > >>>> ---
> > >>>> Changes in v2:
> > >>>> - Drop cci_reg_type enum
> > >>>> - Make having an encoded reg-width mandatory rather then using 0 to encode
> > >>>>   8 bit width making reg-addresses without an encoded width default to
> > >>>>   a width of 8
> > >>>> - Add support for 64 bit wide registers
> > >>
> > >> I'm in two minds about this. This means that the read and write
> > >> functions take a u64 argument, which will be less efficient on 32-bit
> > >> platforms. I think it would be possible, with some macro magic, to
> > >> accept different argument sizes, but maybe that's a micro-optimization
> > >> that would actually result in worse code. 
> > >>
> > >> 64-bit support could be useful, but as far as I can tell, it's not used
> > >> in this series, so maybe we could leave this for later ?
> > > 
> > > I prefer to have it now, I just told Tommaso working on the Alvium driver
> > > to use this, and he needs 64-bit access. :-)
> > > 
> > > You could also easily have 32-bit and 64-bit variant of the functions, with
> > > C11 _Generic(). Introducing it now would be easier than later.
> > 
> > I took a quick look at C11 _Generic() and that looks at the type
> > of "things" so in this case it would look at type of the val argument.
> > 
> > Problem is that that can still be e.g. an int when doing a
> > read/write from a 64 bit registers.
> > 
> > So we would then need to handle the 64 bit width case in the 32
> > bit versions of the functions too.
> > 
> > And likewise I can see someone passing a long on a 64 bit
> > arch while doing a cci_write() to a non 64 bit register.
> > 
> > So this would basically mean copy and pasting cci_read()
> > + cci_write() 2x with the only difference being one
> > variant taking a 32 bit val argument and the other a
> > 64 bit val argument.
> > 
> > This seems like premature optimization to me.
> > 
> > As mentioned in my reply to Laurent if we want to
> > optimize things we really should look at avoiding
> > unnecessary i2c transfers, or packing multiple
> > writes into a single i2c transfer for writes to
> > subsequent registers. That is where significant
> > speedups can be made.
> 
> This is something I'd really like to see, but it's way more work.
> 
> There's an important need of applying changes atomically, which is often
> not possible to strictly guarantee over I2C. Userspace ends up writing
> V4L2 controls as quickly as it can after the start of a frame, hoping
> they will all reach the sensor before the end of the frame. Some
> platforms have camera-specific I2C controllers that have the ability to
> buffer I2C transfers and issue them based on a hardware trigger. How to
> fit this in thé kernel I2C API will be an interesting exercise.
> 
> -- 
> Regards,
> 
> Laurent Pinchart
Sakari Ailus June 15, 2023, 10:08 a.m. UTC | #14
Hi Hans,

On Thu, Jun 15, 2023 at 11:11:20AM +0200, Hans de Goede wrote:
> Hi Sakari,
> 
> On 6/14/23 23:48, Sakari Ailus wrote:
> > Hi Laurent,
> > 
> > On Thu, Jun 15, 2023 at 12:34:29AM +0300, Laurent Pinchart wrote:
> >> Hello,
> >>
> >> On Wed, Jun 14, 2023 at 08:39:56PM +0000, Sakari Ailus wrote:
> >>> On Wed, Jun 14, 2023 at 09:23:39PM +0200, Hans de Goede wrote:
> >>>> The CSI2 specification specifies a standard method to access camera sensor
> >>>> registers called "Camera Control Interface (CCI)".
> >>>>
> >>>> This uses either 8 or 16 bit (big-endian wire order) register addresses
> >>>> and supports 8, 16, 24 or 32 bit (big-endian wire order) register widths.
> >>>>
> >>>> Currently a lot of Linux camera sensor drivers all have their own custom
> >>>> helpers for this, often copy and pasted from other drivers.
> >>>>
> >>>> Add a set of generic helpers for this so that all sensor drivers can
> >>>> switch to a single common implementation.
> >>>>
> >>>> These helpers take an extra optional "int *err" function parameter,
> >>>> this can be used to chain a bunch of register accesses together with
> >>>> only a single error check at the end, rather then needing to error
> >>>> check each individual register access. The first failing call will
> >>>> set the contents of err to a non 0 value and all other calls will
> >>>> then become no-ops.
> >>>>
> >>>> Link: https://lore.kernel.org/linux-media/59aefa7f-7bf9-6736-6040-39551329cd0a@redhat.com/
> >>>> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
> >>>> ---
> >>>> Changes in v2:
> >>>> - Drop cci_reg_type enum
> >>>> - Make having an encoded reg-width mandatory rather then using 0 to encode
> >>>>   8 bit width making reg-addresses without an encoded width default to
> >>>>   a width of 8
> >>>> - Add support for 64 bit wide registers
> >>
> >> I'm in two minds about this. This means that the read and write
> >> functions take a u64 argument, which will be less efficient on 32-bit
> >> platforms. I think it would be possible, with some macro magic, to
> >> accept different argument sizes, but maybe that's a micro-optimization
> >> that would actually result in worse code. 
> >>
> >> 64-bit support could be useful, but as far as I can tell, it's not used
> >> in this series, so maybe we could leave this for later ?
> > 
> > I prefer to have it now, I just told Tommaso working on the Alvium driver
> > to use this, and he needs 64-bit access. :-)
> > 
> > You could also easily have 32-bit and 64-bit variant of the functions, with
> > C11 _Generic(). Introducing it now would be easier than later.
> 
> I took a quick look at C11 _Generic() and that looks at the type
> of "things" so in this case it would look at type of the val argument.
> 
> Problem is that that can still be e.g. an int when doing a
> read/write from a 64 bit registers.

I suppose the compiler would warn you in that case, the same way it would
without _Generic().

> 
> So we would then need to handle the 64 bit width case in the 32
> bit versions of the functions too.

I'd feel annoyed having to have a u64 to read an 8-bit register. But
maybe that's not an issue in practice after all. Just extra memory used for
no reason (register lists).

> 
> And likewise I can see someone passing a long on a 64 bit
> arch while doing a cci_write() to a non 64 bit register.
> 
> So this would basically mean copy and pasting cci_read()
> + cci_write() 2x with the only difference being one
> variant taking a 32 bit val argument and the other a
> 64 bit val argument.
> 
> This seems like premature optimization to me.

Perhaps so, but it's difficult to do that later. Or, well, you can
introduce the 32-bit variant but you'd have to change users in order to use
it in existing code. That's unlikely to happen.

> 
> As mentioned in my reply to Laurent if we want to
> optimize things we really should look at avoiding
> unnecessary i2c transfers, or packing multiple
> writes into a single i2c transfer for writes to
> subsequent registers. That is where significant
> speedups can be made.

In the latter case, yes, there's something that can be done in the CCI
code. Then there are also devices that aren't fully compatible but require
e.g. 8-bit read and/or write access. We need e.g. flags so the driver can
tell not to merge writes. I haven't checked if there's already something in
regmap flags we could use in that case.
Hans de Goede June 15, 2023, 10:15 a.m. UTC | #15
Hi,

On 6/15/23 11:54, Sakari Ailus wrote:
> Hi Hans,
> 
> On Thu, Jun 15, 2023 at 10:45:35AM +0200, Hans de Goede wrote:
>> Hi Sakari,
>>
>> On 6/14/23 22:39, Sakari Ailus wrote:
> 
> ...
>>>> diff --git a/drivers/media/v4l2-core/Kconfig b/drivers/media/v4l2-core/Kconfig
>>>> index 348559bc2468..523ba243261d 100644
>>>> --- a/drivers/media/v4l2-core/Kconfig
>>>> +++ b/drivers/media/v4l2-core/Kconfig
>>>> @@ -74,6 +74,11 @@ config V4L2_FWNODE
>>>>  config V4L2_ASYNC
>>>>  	tristate
>>>>  
>>>> +config V4L2_CCI
>>>> +	tristate
>>>> +	depends on I2C
>>>
>>> This won't do anything if the dependent driver will select V4L2_CCI, will
>>> it? I'd let the sensor driver depend on I2C instead. CCI is also supported
>>> on I3C, for instance.
>>
>> It will cause a Kconfig error if the dependent driver does not depend
>> on I2C. Kconfig items doing select MUST depend on all the depends on
>> of the items they are selecting; and (continued below)
> 
> Maybe this has changed? It used to be that these cases were silently
> ignored and it wasn't that long ago. I haven't been following this up.
> 
> Nevertheless, this shouldn't depend on I2C as such.
> 
>>
>>>
>>>> +	select REGMAP_I2C
>>>
>>> This is a good question.
>>>
>>> How about adding V4L2_CCI_I2C that would select REGMAP_I2C?
>>
>> v4l2-cci.ko uses the devm_regmap_init_i2c() symbol, so
>> REGMAP_I2C must be enabled when V4L2_CCI is enabled and
>> REGMAP_I2C is a symbol which should be selected rather
>> then depended on when necessary.
> 
> I agree.

If you agree that because of the symbol dependency that
the select REGMAP_I2C is necessary then the depends on I2C
is also necessary because any Kconfig symbol selecting
another symbol MUST depends on all of the dependencies
of the selected symbol and REGMAP_I2C has:

config REGMAP_I2C
        tristate
        depends on I2C

<snip>

> This is documented in
> Documentation/driver-api/media/maintainer-entry-profile.rst and media tree
> follows that.

Ah, I missed that. Ok, I'll run

./scripts/checkpatch.pl --strict --max-line-length=80

and fix the warnings, with maybe one or 2 exceptions
where longer lines really make the code more readable.

Regards,

Hans
Andy Shevchenko June 15, 2023, 10:35 a.m. UTC | #16
On Thu, Jun 15, 2023 at 12:15:47PM +0200, Hans de Goede wrote:
> On 6/15/23 11:54, Sakari Ailus wrote:
> > On Thu, Jun 15, 2023 at 10:45:35AM +0200, Hans de Goede wrote:
> >> On 6/14/23 22:39, Sakari Ailus wrote:

...

> > This is documented in
> > Documentation/driver-api/media/maintainer-entry-profile.rst and media tree
> > follows that.
> 
> Ah, I missed that. Ok, I'll run
> 
> ./scripts/checkpatch.pl --strict --max-line-length=80
> 
> and fix the warnings, with maybe one or 2 exceptions
> where longer lines really make the code more readable.

No objection from me.
Hans de Goede June 15, 2023, 11:10 a.m. UTC | #17
Hi Tommaso,

On 6/15/23 12:05, Tommaso Merciai wrote:
> Hi Hans, Laurent, Sakari,
> 
> Can I cherry-pick this patch and use these new functions also
> for cci regs of the alvium driver?

Yes that sounds like a good plan.

> Are on going to be merge?

Yes this will hopefully get merged upstream soon.

Note I'm about to send out a v3 addressing some small
remarks on this v2. I'll Cc you on that.

Regards,

Hans


> 
> Let me know.
> Thanks! :)
> 
> Regards,
> Tommaso
> 
> On Thu, Jun 15, 2023 at 12:21:00PM +0300, Laurent Pinchart wrote:
>> On Thu, Jun 15, 2023 at 11:11:20AM +0200, Hans de Goede wrote:
>>> Hi Sakari,
>>>
>>> On 6/14/23 23:48, Sakari Ailus wrote:
>>>> Hi Laurent,
>>>>
>>>> On Thu, Jun 15, 2023 at 12:34:29AM +0300, Laurent Pinchart wrote:
>>>>> Hello,
>>>>>
>>>>> On Wed, Jun 14, 2023 at 08:39:56PM +0000, Sakari Ailus wrote:
>>>>>> On Wed, Jun 14, 2023 at 09:23:39PM +0200, Hans de Goede wrote:
>>>>>>> The CSI2 specification specifies a standard method to access camera sensor
>>>>>>> registers called "Camera Control Interface (CCI)".
>>>>>>>
>>>>>>> This uses either 8 or 16 bit (big-endian wire order) register addresses
>>>>>>> and supports 8, 16, 24 or 32 bit (big-endian wire order) register widths.
>>>>>>>
>>>>>>> Currently a lot of Linux camera sensor drivers all have their own custom
>>>>>>> helpers for this, often copy and pasted from other drivers.
>>>>>>>
>>>>>>> Add a set of generic helpers for this so that all sensor drivers can
>>>>>>> switch to a single common implementation.
>>>>>>>
>>>>>>> These helpers take an extra optional "int *err" function parameter,
>>>>>>> this can be used to chain a bunch of register accesses together with
>>>>>>> only a single error check at the end, rather then needing to error
>>>>>>> check each individual register access. The first failing call will
>>>>>>> set the contents of err to a non 0 value and all other calls will
>>>>>>> then become no-ops.
>>>>>>>
>>>>>>> Link: https://lore.kernel.org/linux-media/59aefa7f-7bf9-6736-6040-39551329cd0a@redhat.com/
>>>>>>> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
>>>>>>> ---
>>>>>>> Changes in v2:
>>>>>>> - Drop cci_reg_type enum
>>>>>>> - Make having an encoded reg-width mandatory rather then using 0 to encode
>>>>>>>   8 bit width making reg-addresses without an encoded width default to
>>>>>>>   a width of 8
>>>>>>> - Add support for 64 bit wide registers
>>>>>
>>>>> I'm in two minds about this. This means that the read and write
>>>>> functions take a u64 argument, which will be less efficient on 32-bit
>>>>> platforms. I think it would be possible, with some macro magic, to
>>>>> accept different argument sizes, but maybe that's a micro-optimization
>>>>> that would actually result in worse code. 
>>>>>
>>>>> 64-bit support could be useful, but as far as I can tell, it's not used
>>>>> in this series, so maybe we could leave this for later ?
>>>>
>>>> I prefer to have it now, I just told Tommaso working on the Alvium driver
>>>> to use this, and he needs 64-bit access. :-)
>>>>
>>>> You could also easily have 32-bit and 64-bit variant of the functions, with
>>>> C11 _Generic(). Introducing it now would be easier than later.
>>>
>>> I took a quick look at C11 _Generic() and that looks at the type
>>> of "things" so in this case it would look at type of the val argument.
>>>
>>> Problem is that that can still be e.g. an int when doing a
>>> read/write from a 64 bit registers.
>>>
>>> So we would then need to handle the 64 bit width case in the 32
>>> bit versions of the functions too.
>>>
>>> And likewise I can see someone passing a long on a 64 bit
>>> arch while doing a cci_write() to a non 64 bit register.
>>>
>>> So this would basically mean copy and pasting cci_read()
>>> + cci_write() 2x with the only difference being one
>>> variant taking a 32 bit val argument and the other a
>>> 64 bit val argument.
>>>
>>> This seems like premature optimization to me.
>>>
>>> As mentioned in my reply to Laurent if we want to
>>> optimize things we really should look at avoiding
>>> unnecessary i2c transfers, or packing multiple
>>> writes into a single i2c transfer for writes to
>>> subsequent registers. That is where significant
>>> speedups can be made.
>>
>> This is something I'd really like to see, but it's way more work.
>>
>> There's an important need of applying changes atomically, which is often
>> not possible to strictly guarantee over I2C. Userspace ends up writing
>> V4L2 controls as quickly as it can after the start of a frame, hoping
>> they will all reach the sensor before the end of the frame. Some
>> platforms have camera-specific I2C controllers that have the ability to
>> buffer I2C transfers and issue them based on a hardware trigger. How to
>> fit this in thé kernel I2C API will be an interesting exercise.
>>
>> -- 
>> Regards,
>>
>> Laurent Pinchart
>
Tommaso Merciai June 15, 2023, 11:26 a.m. UTC | #18
Hi Hans,

On Thu, Jun 15, 2023 at 01:10:40PM +0200, Hans de Goede wrote:
> Hi Tommaso,
> 
> On 6/15/23 12:05, Tommaso Merciai wrote:
> > Hi Hans, Laurent, Sakari,
> > 
> > Can I cherry-pick this patch and use these new functions also
> > for cci regs of the alvium driver?
> 
> Yes that sounds like a good plan.
> 
> > Are on going to be merge?
> 
> Yes this will hopefully get merged upstream soon.

Thanks for the info!

I want to ask you your opinion about this:

Into alvium driver actually I'm using the following defines
manipulations:

#define REG_BCRM_REG_ADDR_R				REG_BCRM_CCI_16BIT(0x0014)

#define REG_BCRM_FEATURE_INQUIRY_R			REG_BCRM_V4L2_64BIT(0x0008)
#define REG_BCRM_DEVICE_FIRMWARE_VERSION_R		REG_BCRM_V4L2_64BIT(0x0010)

My plan is to use your cci API for cci register in this way defines
became like:

#define REG_BCRM_REG_ADDR_R				CCI_REG16(0x0014)

And leave v4l2 regs are it are right now:

#define REG_BCRM_FEATURE_INQUIRY_R			REG_BCRM_V4L2_64BIT(0x0008)
#define REG_BCRM_DEVICE_FIRMWARE_VERSION_R		REG_BCRM_V4L2_64BIT(0x0010)

What do you think about?

> 
> Note I'm about to send out a v3 addressing some small
> remarks on this v2. I'll Cc you on that.

Thanks, in this way I can test that and let you know my feedback.

Regards,
Tommaso

> 
> Regards,
> 
> Hans
> 
> 
> > 
> > Let me know.
> > Thanks! :)
> > 
> > Regards,
> > Tommaso
> > 
> > On Thu, Jun 15, 2023 at 12:21:00PM +0300, Laurent Pinchart wrote:
> >> On Thu, Jun 15, 2023 at 11:11:20AM +0200, Hans de Goede wrote:
> >>> Hi Sakari,
> >>>
> >>> On 6/14/23 23:48, Sakari Ailus wrote:
> >>>> Hi Laurent,
> >>>>
> >>>> On Thu, Jun 15, 2023 at 12:34:29AM +0300, Laurent Pinchart wrote:
> >>>>> Hello,
> >>>>>
> >>>>> On Wed, Jun 14, 2023 at 08:39:56PM +0000, Sakari Ailus wrote:
> >>>>>> On Wed, Jun 14, 2023 at 09:23:39PM +0200, Hans de Goede wrote:
> >>>>>>> The CSI2 specification specifies a standard method to access camera sensor
> >>>>>>> registers called "Camera Control Interface (CCI)".
> >>>>>>>
> >>>>>>> This uses either 8 or 16 bit (big-endian wire order) register addresses
> >>>>>>> and supports 8, 16, 24 or 32 bit (big-endian wire order) register widths.
> >>>>>>>
> >>>>>>> Currently a lot of Linux camera sensor drivers all have their own custom
> >>>>>>> helpers for this, often copy and pasted from other drivers.
> >>>>>>>
> >>>>>>> Add a set of generic helpers for this so that all sensor drivers can
> >>>>>>> switch to a single common implementation.
> >>>>>>>
> >>>>>>> These helpers take an extra optional "int *err" function parameter,
> >>>>>>> this can be used to chain a bunch of register accesses together with
> >>>>>>> only a single error check at the end, rather then needing to error
> >>>>>>> check each individual register access. The first failing call will
> >>>>>>> set the contents of err to a non 0 value and all other calls will
> >>>>>>> then become no-ops.
> >>>>>>>
> >>>>>>> Link: https://lore.kernel.org/linux-media/59aefa7f-7bf9-6736-6040-39551329cd0a@redhat.com/
> >>>>>>> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
> >>>>>>> ---
> >>>>>>> Changes in v2:
> >>>>>>> - Drop cci_reg_type enum
> >>>>>>> - Make having an encoded reg-width mandatory rather then using 0 to encode
> >>>>>>>   8 bit width making reg-addresses without an encoded width default to
> >>>>>>>   a width of 8
> >>>>>>> - Add support for 64 bit wide registers
> >>>>>
> >>>>> I'm in two minds about this. This means that the read and write
> >>>>> functions take a u64 argument, which will be less efficient on 32-bit
> >>>>> platforms. I think it would be possible, with some macro magic, to
> >>>>> accept different argument sizes, but maybe that's a micro-optimization
> >>>>> that would actually result in worse code. 
> >>>>>
> >>>>> 64-bit support could be useful, but as far as I can tell, it's not used
> >>>>> in this series, so maybe we could leave this for later ?
> >>>>
> >>>> I prefer to have it now, I just told Tommaso working on the Alvium driver
> >>>> to use this, and he needs 64-bit access. :-)
> >>>>
> >>>> You could also easily have 32-bit and 64-bit variant of the functions, with
> >>>> C11 _Generic(). Introducing it now would be easier than later.
> >>>
> >>> I took a quick look at C11 _Generic() and that looks at the type
> >>> of "things" so in this case it would look at type of the val argument.
> >>>
> >>> Problem is that that can still be e.g. an int when doing a
> >>> read/write from a 64 bit registers.
> >>>
> >>> So we would then need to handle the 64 bit width case in the 32
> >>> bit versions of the functions too.
> >>>
> >>> And likewise I can see someone passing a long on a 64 bit
> >>> arch while doing a cci_write() to a non 64 bit register.
> >>>
> >>> So this would basically mean copy and pasting cci_read()
> >>> + cci_write() 2x with the only difference being one
> >>> variant taking a 32 bit val argument and the other a
> >>> 64 bit val argument.
> >>>
> >>> This seems like premature optimization to me.
> >>>
> >>> As mentioned in my reply to Laurent if we want to
> >>> optimize things we really should look at avoiding
> >>> unnecessary i2c transfers, or packing multiple
> >>> writes into a single i2c transfer for writes to
> >>> subsequent registers. That is where significant
> >>> speedups can be made.
> >>
> >> This is something I'd really like to see, but it's way more work.
> >>
> >> There's an important need of applying changes atomically, which is often
> >> not possible to strictly guarantee over I2C. Userspace ends up writing
> >> V4L2 controls as quickly as it can after the start of a frame, hoping
> >> they will all reach the sensor before the end of the frame. Some
> >> platforms have camera-specific I2C controllers that have the ability to
> >> buffer I2C transfers and issue them based on a hardware trigger. How to
> >> fit this in thé kernel I2C API will be an interesting exercise.
> >>
> >> -- 
> >> Regards,
> >>
> >> Laurent Pinchart
> > 
>
Sakari Ailus June 15, 2023, 11:41 a.m. UTC | #19
Hi Hans,

On Thu, Jun 15, 2023 at 12:15:47PM +0200, Hans de Goede wrote:
> Hi,
> 
> On 6/15/23 11:54, Sakari Ailus wrote:
> > Hi Hans,
> > 
> > On Thu, Jun 15, 2023 at 10:45:35AM +0200, Hans de Goede wrote:
> >> Hi Sakari,
> >>
> >> On 6/14/23 22:39, Sakari Ailus wrote:
> > 
> > ...
> >>>> diff --git a/drivers/media/v4l2-core/Kconfig b/drivers/media/v4l2-core/Kconfig
> >>>> index 348559bc2468..523ba243261d 100644
> >>>> --- a/drivers/media/v4l2-core/Kconfig
> >>>> +++ b/drivers/media/v4l2-core/Kconfig
> >>>> @@ -74,6 +74,11 @@ config V4L2_FWNODE
> >>>>  config V4L2_ASYNC
> >>>>  	tristate
> >>>>  
> >>>> +config V4L2_CCI
> >>>> +	tristate
> >>>> +	depends on I2C
> >>>
> >>> This won't do anything if the dependent driver will select V4L2_CCI, will
> >>> it? I'd let the sensor driver depend on I2C instead. CCI is also supported
> >>> on I3C, for instance.
> >>
> >> It will cause a Kconfig error if the dependent driver does not depend
> >> on I2C. Kconfig items doing select MUST depend on all the depends on
> >> of the items they are selecting; and (continued below)
> > 
> > Maybe this has changed? It used to be that these cases were silently
> > ignored and it wasn't that long ago. I haven't been following this up.
> > 
> > Nevertheless, this shouldn't depend on I2C as such.
> > 
> >>
> >>>
> >>>> +	select REGMAP_I2C
> >>>
> >>> This is a good question.
> >>>
> >>> How about adding V4L2_CCI_I2C that would select REGMAP_I2C?
> >>
> >> v4l2-cci.ko uses the devm_regmap_init_i2c() symbol, so
> >> REGMAP_I2C must be enabled when V4L2_CCI is enabled and
> >> REGMAP_I2C is a symbol which should be selected rather
> >> then depended on when necessary.
> > 
> > I agree.
> 
> If you agree that because of the symbol dependency that
> the select REGMAP_I2C is necessary then the depends on I2C
> is also necessary because any Kconfig symbol selecting
> another symbol MUST depends on all of the dependencies
> of the selected symbol and REGMAP_I2C has:
> 
> config REGMAP_I2C
>         tristate
>         depends on I2C

Yes.

How about putting cci_regmap_init_i2c() behind an #ifdef? Then there
wouldn't be a need for REGMAP_I2C unconditionally, but dependent on I2C.

I guess right now I2C is more or less given in many systems but binding CCI
to it still seems dubious.

> 
> <snip>
> 
> > This is documented in
> > Documentation/driver-api/media/maintainer-entry-profile.rst and media tree
> > follows that.
> 
> Ah, I missed that. Ok, I'll run
> 
> ./scripts/checkpatch.pl --strict --max-line-length=80
> 
> and fix the warnings, with maybe one or 2 exceptions
> where longer lines really make the code more readable.

Thank you.
Tommaso Merciai June 15, 2023, 11:54 a.m. UTC | #20
On Thu, Jun 15, 2023 at 01:26:25PM +0200, Tommaso Merciai wrote:
> Hi Hans,
> 
> On Thu, Jun 15, 2023 at 01:10:40PM +0200, Hans de Goede wrote:
> > Hi Tommaso,
> > 
> > On 6/15/23 12:05, Tommaso Merciai wrote:
> > > Hi Hans, Laurent, Sakari,
> > > 
> > > Can I cherry-pick this patch and use these new functions also
> > > for cci regs of the alvium driver?
> > 
> > Yes that sounds like a good plan.
> > 
> > > Are on going to be merge?
> > 
> > Yes this will hopefully get merged upstream soon.
> 
> Thanks for the info!
> 
> I want to ask you your opinion about this:
> 
> Into alvium driver actually I'm using the following defines
> manipulations:
> 
> #define REG_BCRM_REG_ADDR_R				REG_BCRM_CCI_16BIT(0x0014)
> 
> #define REG_BCRM_FEATURE_INQUIRY_R			REG_BCRM_V4L2_64BIT(0x0008)
> #define REG_BCRM_DEVICE_FIRMWARE_VERSION_R		REG_BCRM_V4L2_64BIT(0x0010)
> 
> My plan is to use your cci API for cci register in this way defines
> became like:
> 
> #define REG_BCRM_REG_ADDR_R				CCI_REG16(0x0014)
> 
> And leave v4l2 regs are it are right now:
> 
> #define REG_BCRM_FEATURE_INQUIRY_R			REG_BCRM_V4L2_64BIT(0x0008)
> #define REG_BCRM_DEVICE_FIRMWARE_VERSION_R		REG_BCRM_V4L2_64BIT(0x0010)
> 
> What do you think about?

Or maybe is worth don't use v4l2 bit for v4l2 regs, I think is implicit
that what regs that are not CCI are v4l2, then we return wit the
following defines:



#define REG_BCRM_REG_ADDR_R                           CCI_REG16(0x0014)
^CCI regs

#define REG_BCRM_FEATURE_INQUIRY_R                    0x0008 
#define REG_BCRM_DEVICE_FIRMWARE_VERSION_R            0x0010
^v4l2 regs

?

> 
> > 
> > Note I'm about to send out a v3 addressing some small
> > remarks on this v2. I'll Cc you on that.
> 
> Thanks, in this way I can test that and let you know my feedback.
> 
> Regards,
> Tommaso
> 
> > 
> > Regards,
> > 
> > Hans
> > 
> > 
> > > 
> > > Let me know.
> > > Thanks! :)
> > > 
> > > Regards,
> > > Tommaso
> > > 
> > > On Thu, Jun 15, 2023 at 12:21:00PM +0300, Laurent Pinchart wrote:
> > >> On Thu, Jun 15, 2023 at 11:11:20AM +0200, Hans de Goede wrote:
> > >>> Hi Sakari,
> > >>>
> > >>> On 6/14/23 23:48, Sakari Ailus wrote:
> > >>>> Hi Laurent,
> > >>>>
> > >>>> On Thu, Jun 15, 2023 at 12:34:29AM +0300, Laurent Pinchart wrote:
> > >>>>> Hello,
> > >>>>>
> > >>>>> On Wed, Jun 14, 2023 at 08:39:56PM +0000, Sakari Ailus wrote:
> > >>>>>> On Wed, Jun 14, 2023 at 09:23:39PM +0200, Hans de Goede wrote:
> > >>>>>>> The CSI2 specification specifies a standard method to access camera sensor
> > >>>>>>> registers called "Camera Control Interface (CCI)".
> > >>>>>>>
> > >>>>>>> This uses either 8 or 16 bit (big-endian wire order) register addresses
> > >>>>>>> and supports 8, 16, 24 or 32 bit (big-endian wire order) register widths.
> > >>>>>>>
> > >>>>>>> Currently a lot of Linux camera sensor drivers all have their own custom
> > >>>>>>> helpers for this, often copy and pasted from other drivers.
> > >>>>>>>
> > >>>>>>> Add a set of generic helpers for this so that all sensor drivers can
> > >>>>>>> switch to a single common implementation.
> > >>>>>>>
> > >>>>>>> These helpers take an extra optional "int *err" function parameter,
> > >>>>>>> this can be used to chain a bunch of register accesses together with
> > >>>>>>> only a single error check at the end, rather then needing to error
> > >>>>>>> check each individual register access. The first failing call will
> > >>>>>>> set the contents of err to a non 0 value and all other calls will
> > >>>>>>> then become no-ops.
> > >>>>>>>
> > >>>>>>> Link: https://lore.kernel.org/linux-media/59aefa7f-7bf9-6736-6040-39551329cd0a@redhat.com/
> > >>>>>>> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
> > >>>>>>> ---
> > >>>>>>> Changes in v2:
> > >>>>>>> - Drop cci_reg_type enum
> > >>>>>>> - Make having an encoded reg-width mandatory rather then using 0 to encode
> > >>>>>>>   8 bit width making reg-addresses without an encoded width default to
> > >>>>>>>   a width of 8
> > >>>>>>> - Add support for 64 bit wide registers
> > >>>>>
> > >>>>> I'm in two minds about this. This means that the read and write
> > >>>>> functions take a u64 argument, which will be less efficient on 32-bit
> > >>>>> platforms. I think it would be possible, with some macro magic, to
> > >>>>> accept different argument sizes, but maybe that's a micro-optimization
> > >>>>> that would actually result in worse code. 
> > >>>>>
> > >>>>> 64-bit support could be useful, but as far as I can tell, it's not used
> > >>>>> in this series, so maybe we could leave this for later ?
> > >>>>
> > >>>> I prefer to have it now, I just told Tommaso working on the Alvium driver
> > >>>> to use this, and he needs 64-bit access. :-)
> > >>>>
> > >>>> You could also easily have 32-bit and 64-bit variant of the functions, with
> > >>>> C11 _Generic(). Introducing it now would be easier than later.
> > >>>
> > >>> I took a quick look at C11 _Generic() and that looks at the type
> > >>> of "things" so in this case it would look at type of the val argument.
> > >>>
> > >>> Problem is that that can still be e.g. an int when doing a
> > >>> read/write from a 64 bit registers.
> > >>>
> > >>> So we would then need to handle the 64 bit width case in the 32
> > >>> bit versions of the functions too.
> > >>>
> > >>> And likewise I can see someone passing a long on a 64 bit
> > >>> arch while doing a cci_write() to a non 64 bit register.
> > >>>
> > >>> So this would basically mean copy and pasting cci_read()
> > >>> + cci_write() 2x with the only difference being one
> > >>> variant taking a 32 bit val argument and the other a
> > >>> 64 bit val argument.
> > >>>
> > >>> This seems like premature optimization to me.
> > >>>
> > >>> As mentioned in my reply to Laurent if we want to
> > >>> optimize things we really should look at avoiding
> > >>> unnecessary i2c transfers, or packing multiple
> > >>> writes into a single i2c transfer for writes to
> > >>> subsequent registers. That is where significant
> > >>> speedups can be made.
> > >>
> > >> This is something I'd really like to see, but it's way more work.
> > >>
> > >> There's an important need of applying changes atomically, which is often
> > >> not possible to strictly guarantee over I2C. Userspace ends up writing
> > >> V4L2 controls as quickly as it can after the start of a frame, hoping
> > >> they will all reach the sensor before the end of the frame. Some
> > >> platforms have camera-specific I2C controllers that have the ability to
> > >> buffer I2C transfers and issue them based on a hardware trigger. How to
> > >> fit this in thé kernel I2C API will be an interesting exercise.
> > >>
> > >> -- 
> > >> Regards,
> > >>
> > >> Laurent Pinchart
> > > 
> >
Hans de Goede June 15, 2023, noon UTC | #21
Hi,

On 6/15/23 13:54, Tommaso Merciai wrote:
> On Thu, Jun 15, 2023 at 01:26:25PM +0200, Tommaso Merciai wrote:
>> Hi Hans,
>>
>> On Thu, Jun 15, 2023 at 01:10:40PM +0200, Hans de Goede wrote:
>>> Hi Tommaso,
>>>
>>> On 6/15/23 12:05, Tommaso Merciai wrote:
>>>> Hi Hans, Laurent, Sakari,
>>>>
>>>> Can I cherry-pick this patch and use these new functions also
>>>> for cci regs of the alvium driver?
>>>
>>> Yes that sounds like a good plan.
>>>
>>>> Are on going to be merge?
>>>
>>> Yes this will hopefully get merged upstream soon.
>>
>> Thanks for the info!
>>
>> I want to ask you your opinion about this:
>>
>> Into alvium driver actually I'm using the following defines
>> manipulations:
>>
>> #define REG_BCRM_REG_ADDR_R				REG_BCRM_CCI_16BIT(0x0014)
>>
>> #define REG_BCRM_FEATURE_INQUIRY_R			REG_BCRM_V4L2_64BIT(0x0008)
>> #define REG_BCRM_DEVICE_FIRMWARE_VERSION_R		REG_BCRM_V4L2_64BIT(0x0010)
>>
>> My plan is to use your cci API for cci register in this way defines
>> became like:
>>
>> #define REG_BCRM_REG_ADDR_R				CCI_REG16(0x0014)
>>
>> And leave v4l2 regs are it are right now:
>>
>> #define REG_BCRM_FEATURE_INQUIRY_R			REG_BCRM_V4L2_64BIT(0x0008)
>> #define REG_BCRM_DEVICE_FIRMWARE_VERSION_R		REG_BCRM_V4L2_64BIT(0x0010)
>>
>> What do you think about?
> 
> Or maybe is worth don't use v4l2 bit for v4l2 regs, I think is implicit
> that what regs that are not CCI are v4l2, then we return wit the
> following defines:
> 
> 
> 
> #define REG_BCRM_REG_ADDR_R                           CCI_REG16(0x0014)
> ^CCI regs
> 
> #define REG_BCRM_FEATURE_INQUIRY_R                    0x0008 
> #define REG_BCRM_DEVICE_FIRMWARE_VERSION_R            0x0010
> ^v4l2 regs

I'm not sure what you mean with "V4L2" registers ? I guess you mean
registers which cannot be accessed through the CCI helper functions,
but starting with v2 this is no longer true. There now is a CCI_REG64()
so you can simply use that.

Regards,

Hans



> 
> ?
> 
>>
>>>
>>> Note I'm about to send out a v3 addressing some small
>>> remarks on this v2. I'll Cc you on that.
>>
>> Thanks, in this way I can test that and let you know my feedback.
>>
>> Regards,
>> Tommaso
>>
>>>
>>> Regards,
>>>
>>> Hans
>>>
>>>
>>>>
>>>> Let me know.
>>>> Thanks! :)
>>>>
>>>> Regards,
>>>> Tommaso
>>>>
>>>> On Thu, Jun 15, 2023 at 12:21:00PM +0300, Laurent Pinchart wrote:
>>>>> On Thu, Jun 15, 2023 at 11:11:20AM +0200, Hans de Goede wrote:
>>>>>> Hi Sakari,
>>>>>>
>>>>>> On 6/14/23 23:48, Sakari Ailus wrote:
>>>>>>> Hi Laurent,
>>>>>>>
>>>>>>> On Thu, Jun 15, 2023 at 12:34:29AM +0300, Laurent Pinchart wrote:
>>>>>>>> Hello,
>>>>>>>>
>>>>>>>> On Wed, Jun 14, 2023 at 08:39:56PM +0000, Sakari Ailus wrote:
>>>>>>>>> On Wed, Jun 14, 2023 at 09:23:39PM +0200, Hans de Goede wrote:
>>>>>>>>>> The CSI2 specification specifies a standard method to access camera sensor
>>>>>>>>>> registers called "Camera Control Interface (CCI)".
>>>>>>>>>>
>>>>>>>>>> This uses either 8 or 16 bit (big-endian wire order) register addresses
>>>>>>>>>> and supports 8, 16, 24 or 32 bit (big-endian wire order) register widths.
>>>>>>>>>>
>>>>>>>>>> Currently a lot of Linux camera sensor drivers all have their own custom
>>>>>>>>>> helpers for this, often copy and pasted from other drivers.
>>>>>>>>>>
>>>>>>>>>> Add a set of generic helpers for this so that all sensor drivers can
>>>>>>>>>> switch to a single common implementation.
>>>>>>>>>>
>>>>>>>>>> These helpers take an extra optional "int *err" function parameter,
>>>>>>>>>> this can be used to chain a bunch of register accesses together with
>>>>>>>>>> only a single error check at the end, rather then needing to error
>>>>>>>>>> check each individual register access. The first failing call will
>>>>>>>>>> set the contents of err to a non 0 value and all other calls will
>>>>>>>>>> then become no-ops.
>>>>>>>>>>
>>>>>>>>>> Link: https://lore.kernel.org/linux-media/59aefa7f-7bf9-6736-6040-39551329cd0a@redhat.com/
>>>>>>>>>> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
>>>>>>>>>> ---
>>>>>>>>>> Changes in v2:
>>>>>>>>>> - Drop cci_reg_type enum
>>>>>>>>>> - Make having an encoded reg-width mandatory rather then using 0 to encode
>>>>>>>>>>   8 bit width making reg-addresses without an encoded width default to
>>>>>>>>>>   a width of 8
>>>>>>>>>> - Add support for 64 bit wide registers
>>>>>>>>
>>>>>>>> I'm in two minds about this. This means that the read and write
>>>>>>>> functions take a u64 argument, which will be less efficient on 32-bit
>>>>>>>> platforms. I think it would be possible, with some macro magic, to
>>>>>>>> accept different argument sizes, but maybe that's a micro-optimization
>>>>>>>> that would actually result in worse code. 
>>>>>>>>
>>>>>>>> 64-bit support could be useful, but as far as I can tell, it's not used
>>>>>>>> in this series, so maybe we could leave this for later ?
>>>>>>>
>>>>>>> I prefer to have it now, I just told Tommaso working on the Alvium driver
>>>>>>> to use this, and he needs 64-bit access. :-)
>>>>>>>
>>>>>>> You could also easily have 32-bit and 64-bit variant of the functions, with
>>>>>>> C11 _Generic(). Introducing it now would be easier than later.
>>>>>>
>>>>>> I took a quick look at C11 _Generic() and that looks at the type
>>>>>> of "things" so in this case it would look at type of the val argument.
>>>>>>
>>>>>> Problem is that that can still be e.g. an int when doing a
>>>>>> read/write from a 64 bit registers.
>>>>>>
>>>>>> So we would then need to handle the 64 bit width case in the 32
>>>>>> bit versions of the functions too.
>>>>>>
>>>>>> And likewise I can see someone passing a long on a 64 bit
>>>>>> arch while doing a cci_write() to a non 64 bit register.
>>>>>>
>>>>>> So this would basically mean copy and pasting cci_read()
>>>>>> + cci_write() 2x with the only difference being one
>>>>>> variant taking a 32 bit val argument and the other a
>>>>>> 64 bit val argument.
>>>>>>
>>>>>> This seems like premature optimization to me.
>>>>>>
>>>>>> As mentioned in my reply to Laurent if we want to
>>>>>> optimize things we really should look at avoiding
>>>>>> unnecessary i2c transfers, or packing multiple
>>>>>> writes into a single i2c transfer for writes to
>>>>>> subsequent registers. That is where significant
>>>>>> speedups can be made.
>>>>>
>>>>> This is something I'd really like to see, but it's way more work.
>>>>>
>>>>> There's an important need of applying changes atomically, which is often
>>>>> not possible to strictly guarantee over I2C. Userspace ends up writing
>>>>> V4L2 controls as quickly as it can after the start of a frame, hoping
>>>>> they will all reach the sensor before the end of the frame. Some
>>>>> platforms have camera-specific I2C controllers that have the ability to
>>>>> buffer I2C transfers and issue them based on a hardware trigger. How to
>>>>> fit this in thé kernel I2C API will be an interesting exercise.
>>>>>
>>>>> -- 
>>>>> Regards,
>>>>>
>>>>> Laurent Pinchart
>>>>
>>>
>
Hans de Goede June 15, 2023, 12:05 p.m. UTC | #22
Hi,

On 6/15/23 13:41, Sakari Ailus wrote:
> Hi Hans,
> 
> On Thu, Jun 15, 2023 at 12:15:47PM +0200, Hans de Goede wrote:
>> Hi,
>>
>> On 6/15/23 11:54, Sakari Ailus wrote:
>>> Hi Hans,
>>>
>>> On Thu, Jun 15, 2023 at 10:45:35AM +0200, Hans de Goede wrote:
>>>> Hi Sakari,
>>>>
>>>> On 6/14/23 22:39, Sakari Ailus wrote:
>>>
>>> ...
>>>>>> diff --git a/drivers/media/v4l2-core/Kconfig b/drivers/media/v4l2-core/Kconfig
>>>>>> index 348559bc2468..523ba243261d 100644
>>>>>> --- a/drivers/media/v4l2-core/Kconfig
>>>>>> +++ b/drivers/media/v4l2-core/Kconfig
>>>>>> @@ -74,6 +74,11 @@ config V4L2_FWNODE
>>>>>>  config V4L2_ASYNC
>>>>>>  	tristate
>>>>>>  
>>>>>> +config V4L2_CCI
>>>>>> +	tristate
>>>>>> +	depends on I2C
>>>>>
>>>>> This won't do anything if the dependent driver will select V4L2_CCI, will
>>>>> it? I'd let the sensor driver depend on I2C instead. CCI is also supported
>>>>> on I3C, for instance.
>>>>
>>>> It will cause a Kconfig error if the dependent driver does not depend
>>>> on I2C. Kconfig items doing select MUST depend on all the depends on
>>>> of the items they are selecting; and (continued below)
>>>
>>> Maybe this has changed? It used to be that these cases were silently
>>> ignored and it wasn't that long ago. I haven't been following this up.
>>>
>>> Nevertheless, this shouldn't depend on I2C as such.
>>>
>>>>
>>>>>
>>>>>> +	select REGMAP_I2C
>>>>>
>>>>> This is a good question.
>>>>>
>>>>> How about adding V4L2_CCI_I2C that would select REGMAP_I2C?
>>>>
>>>> v4l2-cci.ko uses the devm_regmap_init_i2c() symbol, so
>>>> REGMAP_I2C must be enabled when V4L2_CCI is enabled and
>>>> REGMAP_I2C is a symbol which should be selected rather
>>>> then depended on when necessary.
>>>
>>> I agree.
>>
>> If you agree that because of the symbol dependency that
>> the select REGMAP_I2C is necessary then the depends on I2C
>> is also necessary because any Kconfig symbol selecting
>> another symbol MUST depends on all of the dependencies
>> of the selected symbol and REGMAP_I2C has:
>>
>> config REGMAP_I2C
>>         tristate
>>         depends on I2C
> 
> Yes.
> 
> How about putting cci_regmap_init_i2c() behind an #ifdef? Then there
> wouldn't be a need for REGMAP_I2C unconditionally, but dependent on I2C.
> 
> I guess right now I2C is more or less given in many systems but binding CCI
> to it still seems dubious.

Yes, I can wrap the cci_regmap_init_i2c() prototype +
implementation in

#ifdef CONFIG_REGMAP_I2C

for version 4. Downside of this is that all i2c sensor drivers
which want to use the CCI helpers now will need to have
a select REGMAP_I2C added to their Kconfig snippet.

Regards,

Hans



	

> 
>>
>> <snip>
>>
>>> This is documented in
>>> Documentation/driver-api/media/maintainer-entry-profile.rst and media tree
>>> follows that.
>>
>> Ah, I missed that. Ok, I'll run
>>
>> ./scripts/checkpatch.pl --strict --max-line-length=80
>>
>> and fix the warnings, with maybe one or 2 exceptions
>> where longer lines really make the code more readable.
> 
> Thank you.
>
Sakari Ailus June 15, 2023, 1:19 p.m. UTC | #23
Hi Hans,

On Thu, Jun 15, 2023 at 02:05:02PM +0200, Hans de Goede wrote:
> Hi,
> 
> On 6/15/23 13:41, Sakari Ailus wrote:
> > Hi Hans,
> > 
> > On Thu, Jun 15, 2023 at 12:15:47PM +0200, Hans de Goede wrote:
> >> Hi,
> >>
> >> On 6/15/23 11:54, Sakari Ailus wrote:
> >>> Hi Hans,
> >>>
> >>> On Thu, Jun 15, 2023 at 10:45:35AM +0200, Hans de Goede wrote:
> >>>> Hi Sakari,
> >>>>
> >>>> On 6/14/23 22:39, Sakari Ailus wrote:
> >>>
> >>> ...
> >>>>>> diff --git a/drivers/media/v4l2-core/Kconfig b/drivers/media/v4l2-core/Kconfig
> >>>>>> index 348559bc2468..523ba243261d 100644
> >>>>>> --- a/drivers/media/v4l2-core/Kconfig
> >>>>>> +++ b/drivers/media/v4l2-core/Kconfig
> >>>>>> @@ -74,6 +74,11 @@ config V4L2_FWNODE
> >>>>>>  config V4L2_ASYNC
> >>>>>>  	tristate
> >>>>>>  
> >>>>>> +config V4L2_CCI
> >>>>>> +	tristate
> >>>>>> +	depends on I2C
> >>>>>
> >>>>> This won't do anything if the dependent driver will select V4L2_CCI, will
> >>>>> it? I'd let the sensor driver depend on I2C instead. CCI is also supported
> >>>>> on I3C, for instance.
> >>>>
> >>>> It will cause a Kconfig error if the dependent driver does not depend
> >>>> on I2C. Kconfig items doing select MUST depend on all the depends on
> >>>> of the items they are selecting; and (continued below)
> >>>
> >>> Maybe this has changed? It used to be that these cases were silently
> >>> ignored and it wasn't that long ago. I haven't been following this up.
> >>>
> >>> Nevertheless, this shouldn't depend on I2C as such.
> >>>
> >>>>
> >>>>>
> >>>>>> +	select REGMAP_I2C
> >>>>>
> >>>>> This is a good question.
> >>>>>
> >>>>> How about adding V4L2_CCI_I2C that would select REGMAP_I2C?
> >>>>
> >>>> v4l2-cci.ko uses the devm_regmap_init_i2c() symbol, so
> >>>> REGMAP_I2C must be enabled when V4L2_CCI is enabled and
> >>>> REGMAP_I2C is a symbol which should be selected rather
> >>>> then depended on when necessary.
> >>>
> >>> I agree.
> >>
> >> If you agree that because of the symbol dependency that
> >> the select REGMAP_I2C is necessary then the depends on I2C
> >> is also necessary because any Kconfig symbol selecting
> >> another symbol MUST depends on all of the dependencies
> >> of the selected symbol and REGMAP_I2C has:
> >>
> >> config REGMAP_I2C
> >>         tristate
> >>         depends on I2C
> > 
> > Yes.
> > 
> > How about putting cci_regmap_init_i2c() behind an #ifdef? Then there
> > wouldn't be a need for REGMAP_I2C unconditionally, but dependent on I2C.
> > 
> > I guess right now I2C is more or less given in many systems but binding CCI
> > to it still seems dubious.
> 
> Yes, I can wrap the cci_regmap_init_i2c() prototype +
> implementation in
> 
> #ifdef CONFIG_REGMAP_I2C
> 
> for version 4. Downside of this is that all i2c sensor drivers
> which want to use the CCI helpers now will need to have
> a select REGMAP_I2C added to their Kconfig snippet.

Not if you add a new option for V4L2_CCI, a bit like you suggested for
sensor driver dependencies in general:

config V4L2_CCI_I2C
	tristate
	depends on I2C
	select REGMAP_I2C
	select V4L2_CCI

So individual drivers would then select this instead of the plain V4L2_CCI.

The same could later on be done for I3C.
Andy Shevchenko June 15, 2023, 1:23 p.m. UTC | #24
On Thu, Jun 15, 2023 at 11:41:10AM +0000, Sakari Ailus wrote:
> On Thu, Jun 15, 2023 at 12:15:47PM +0200, Hans de Goede wrote:
> > On 6/15/23 11:54, Sakari Ailus wrote:
> > > On Thu, Jun 15, 2023 at 10:45:35AM +0200, Hans de Goede wrote:
> > >> On 6/14/23 22:39, Sakari Ailus wrote:

...

> > If you agree that because of the symbol dependency that
> > the select REGMAP_I2C is necessary then the depends on I2C
> > is also necessary because any Kconfig symbol selecting
> > another symbol MUST depends on all of the dependencies
> > of the selected symbol and REGMAP_I2C has:
> > 
> > config REGMAP_I2C
> >         tristate
> >         depends on I2C
> 
> Yes.
> 
> How about putting cci_regmap_init_i2c() behind an #ifdef? Then there
> wouldn't be a need for REGMAP_I2C unconditionally, but dependent on I2C.
> 
> I guess right now I2C is more or less given in many systems but binding CCI
> to it still seems dubious.

Can't we solve the issue when it comes?
What you are suggesting seems controversial to me at this stage.
Sakari Ailus June 15, 2023, 1:28 p.m. UTC | #25
On Thu, Jun 15, 2023 at 01:19:30PM +0000, Sakari Ailus wrote:
> Hi Hans,
> 
> On Thu, Jun 15, 2023 at 02:05:02PM +0200, Hans de Goede wrote:
> > Hi,
> > 
> > On 6/15/23 13:41, Sakari Ailus wrote:
> > > Hi Hans,
> > > 
> > > On Thu, Jun 15, 2023 at 12:15:47PM +0200, Hans de Goede wrote:
> > >> Hi,
> > >>
> > >> On 6/15/23 11:54, Sakari Ailus wrote:
> > >>> Hi Hans,
> > >>>
> > >>> On Thu, Jun 15, 2023 at 10:45:35AM +0200, Hans de Goede wrote:
> > >>>> Hi Sakari,
> > >>>>
> > >>>> On 6/14/23 22:39, Sakari Ailus wrote:
> > >>>
> > >>> ...
> > >>>>>> diff --git a/drivers/media/v4l2-core/Kconfig b/drivers/media/v4l2-core/Kconfig
> > >>>>>> index 348559bc2468..523ba243261d 100644
> > >>>>>> --- a/drivers/media/v4l2-core/Kconfig
> > >>>>>> +++ b/drivers/media/v4l2-core/Kconfig
> > >>>>>> @@ -74,6 +74,11 @@ config V4L2_FWNODE
> > >>>>>>  config V4L2_ASYNC
> > >>>>>>  	tristate
> > >>>>>>  
> > >>>>>> +config V4L2_CCI
> > >>>>>> +	tristate
> > >>>>>> +	depends on I2C
> > >>>>>
> > >>>>> This won't do anything if the dependent driver will select V4L2_CCI, will
> > >>>>> it? I'd let the sensor driver depend on I2C instead. CCI is also supported
> > >>>>> on I3C, for instance.
> > >>>>
> > >>>> It will cause a Kconfig error if the dependent driver does not depend
> > >>>> on I2C. Kconfig items doing select MUST depend on all the depends on
> > >>>> of the items they are selecting; and (continued below)
> > >>>
> > >>> Maybe this has changed? It used to be that these cases were silently
> > >>> ignored and it wasn't that long ago. I haven't been following this up.
> > >>>
> > >>> Nevertheless, this shouldn't depend on I2C as such.
> > >>>
> > >>>>
> > >>>>>
> > >>>>>> +	select REGMAP_I2C
> > >>>>>
> > >>>>> This is a good question.
> > >>>>>
> > >>>>> How about adding V4L2_CCI_I2C that would select REGMAP_I2C?
> > >>>>
> > >>>> v4l2-cci.ko uses the devm_regmap_init_i2c() symbol, so
> > >>>> REGMAP_I2C must be enabled when V4L2_CCI is enabled and
> > >>>> REGMAP_I2C is a symbol which should be selected rather
> > >>>> then depended on when necessary.
> > >>>
> > >>> I agree.
> > >>
> > >> If you agree that because of the symbol dependency that
> > >> the select REGMAP_I2C is necessary then the depends on I2C
> > >> is also necessary because any Kconfig symbol selecting
> > >> another symbol MUST depends on all of the dependencies
> > >> of the selected symbol and REGMAP_I2C has:
> > >>
> > >> config REGMAP_I2C
> > >>         tristate
> > >>         depends on I2C
> > > 
> > > Yes.
> > > 
> > > How about putting cci_regmap_init_i2c() behind an #ifdef? Then there
> > > wouldn't be a need for REGMAP_I2C unconditionally, but dependent on I2C.
> > > 
> > > I guess right now I2C is more or less given in many systems but binding CCI
> > > to it still seems dubious.
> > 
> > Yes, I can wrap the cci_regmap_init_i2c() prototype +
> > implementation in
> > 
> > #ifdef CONFIG_REGMAP_I2C
> > 
> > for version 4. Downside of this is that all i2c sensor drivers
> > which want to use the CCI helpers now will need to have
> > a select REGMAP_I2C added to their Kconfig snippet.
> 
> Not if you add a new option for V4L2_CCI, a bit like you suggested for
> sensor driver dependencies in general:
> 
> config V4L2_CCI_I2C
> 	tristate
> 	depends on I2C
> 	select REGMAP_I2C
> 	select V4L2_CCI
> 
> So individual drivers would then select this instead of the plain V4L2_CCI.

In fact nearly the same can be achieved by just renaming V4L2_CCI
V4L2_CCI_I2C now.
Hans de Goede June 15, 2023, 1:52 p.m. UTC | #26
Hi,

On 6/15/23 15:19, Sakari Ailus wrote:
> Hi Hans,
> 
> On Thu, Jun 15, 2023 at 02:05:02PM +0200, Hans de Goede wrote:
>> Hi,
>>
>> On 6/15/23 13:41, Sakari Ailus wrote:
>>> Hi Hans,
>>>
>>> On Thu, Jun 15, 2023 at 12:15:47PM +0200, Hans de Goede wrote:
>>>> Hi,
>>>>
>>>> On 6/15/23 11:54, Sakari Ailus wrote:
>>>>> Hi Hans,
>>>>>
>>>>> On Thu, Jun 15, 2023 at 10:45:35AM +0200, Hans de Goede wrote:
>>>>>> Hi Sakari,
>>>>>>
>>>>>> On 6/14/23 22:39, Sakari Ailus wrote:
>>>>>
>>>>> ...
>>>>>>>> diff --git a/drivers/media/v4l2-core/Kconfig b/drivers/media/v4l2-core/Kconfig
>>>>>>>> index 348559bc2468..523ba243261d 100644
>>>>>>>> --- a/drivers/media/v4l2-core/Kconfig
>>>>>>>> +++ b/drivers/media/v4l2-core/Kconfig
>>>>>>>> @@ -74,6 +74,11 @@ config V4L2_FWNODE
>>>>>>>>  config V4L2_ASYNC
>>>>>>>>  	tristate
>>>>>>>>  
>>>>>>>> +config V4L2_CCI
>>>>>>>> +	tristate
>>>>>>>> +	depends on I2C
>>>>>>>
>>>>>>> This won't do anything if the dependent driver will select V4L2_CCI, will
>>>>>>> it? I'd let the sensor driver depend on I2C instead. CCI is also supported
>>>>>>> on I3C, for instance.
>>>>>>
>>>>>> It will cause a Kconfig error if the dependent driver does not depend
>>>>>> on I2C. Kconfig items doing select MUST depend on all the depends on
>>>>>> of the items they are selecting; and (continued below)
>>>>>
>>>>> Maybe this has changed? It used to be that these cases were silently
>>>>> ignored and it wasn't that long ago. I haven't been following this up.
>>>>>
>>>>> Nevertheless, this shouldn't depend on I2C as such.
>>>>>
>>>>>>
>>>>>>>
>>>>>>>> +	select REGMAP_I2C
>>>>>>>
>>>>>>> This is a good question.
>>>>>>>
>>>>>>> How about adding V4L2_CCI_I2C that would select REGMAP_I2C?
>>>>>>
>>>>>> v4l2-cci.ko uses the devm_regmap_init_i2c() symbol, so
>>>>>> REGMAP_I2C must be enabled when V4L2_CCI is enabled and
>>>>>> REGMAP_I2C is a symbol which should be selected rather
>>>>>> then depended on when necessary.
>>>>>
>>>>> I agree.
>>>>
>>>> If you agree that because of the symbol dependency that
>>>> the select REGMAP_I2C is necessary then the depends on I2C
>>>> is also necessary because any Kconfig symbol selecting
>>>> another symbol MUST depends on all of the dependencies
>>>> of the selected symbol and REGMAP_I2C has:
>>>>
>>>> config REGMAP_I2C
>>>>         tristate
>>>>         depends on I2C
>>>
>>> Yes.
>>>
>>> How about putting cci_regmap_init_i2c() behind an #ifdef? Then there
>>> wouldn't be a need for REGMAP_I2C unconditionally, but dependent on I2C.
>>>
>>> I guess right now I2C is more or less given in many systems but binding CCI
>>> to it still seems dubious.
>>
>> Yes, I can wrap the cci_regmap_init_i2c() prototype +
>> implementation in
>>
>> #ifdef CONFIG_REGMAP_I2C
>>
>> for version 4. Downside of this is that all i2c sensor drivers
>> which want to use the CCI helpers now will need to have
>> a select REGMAP_I2C added to their Kconfig snippet.
> 
> Not if you add a new option for V4L2_CCI, a bit like you suggested for
> sensor driver dependencies in general:
> 
> config V4L2_CCI_I2C
> 	tristate
> 	depends on I2C
> 	select REGMAP_I2C
> 	select V4L2_CCI
> 
> So individual drivers would then select this instead of the plain V4L2_CCI.
> 
> The same could later on be done for I3C.

Ack, I'll do that for v4. But first lets see if there is
going to be more feedback on v3.

Regards,

Hans
Tommaso Merciai June 15, 2023, 4:15 p.m. UTC | #27
Hi Hans,

On Thu, Jun 15, 2023 at 02:00:46PM +0200, Hans de Goede wrote:
> Hi,
> 
> On 6/15/23 13:54, Tommaso Merciai wrote:
> > On Thu, Jun 15, 2023 at 01:26:25PM +0200, Tommaso Merciai wrote:
> >> Hi Hans,
> >>
> >> On Thu, Jun 15, 2023 at 01:10:40PM +0200, Hans de Goede wrote:
> >>> Hi Tommaso,
> >>>
> >>> On 6/15/23 12:05, Tommaso Merciai wrote:
> >>>> Hi Hans, Laurent, Sakari,
> >>>>
> >>>> Can I cherry-pick this patch and use these new functions also
> >>>> for cci regs of the alvium driver?
> >>>
> >>> Yes that sounds like a good plan.
> >>>
> >>>> Are on going to be merge?
> >>>
> >>> Yes this will hopefully get merged upstream soon.
> >>
> >> Thanks for the info!
> >>
> >> I want to ask you your opinion about this:
> >>
> >> Into alvium driver actually I'm using the following defines
> >> manipulations:
> >>
> >> #define REG_BCRM_REG_ADDR_R				REG_BCRM_CCI_16BIT(0x0014)
> >>
> >> #define REG_BCRM_FEATURE_INQUIRY_R			REG_BCRM_V4L2_64BIT(0x0008)
> >> #define REG_BCRM_DEVICE_FIRMWARE_VERSION_R		REG_BCRM_V4L2_64BIT(0x0010)
> >>
> >> My plan is to use your cci API for cci register in this way defines
> >> became like:
> >>
> >> #define REG_BCRM_REG_ADDR_R				CCI_REG16(0x0014)
> >>
> >> And leave v4l2 regs are it are right now:
> >>
> >> #define REG_BCRM_FEATURE_INQUIRY_R			REG_BCRM_V4L2_64BIT(0x0008)
> >> #define REG_BCRM_DEVICE_FIRMWARE_VERSION_R		REG_BCRM_V4L2_64BIT(0x0010)
> >>
> >> What do you think about?
> > 
> > Or maybe is worth don't use v4l2 bit for v4l2 regs, I think is implicit
> > that what regs that are not CCI are v4l2, then we return wit the
> > following defines:
> > 
> > 
> > 
> > #define REG_BCRM_REG_ADDR_R                           CCI_REG16(0x0014)
> > ^CCI regs
> > 
> > #define REG_BCRM_FEATURE_INQUIRY_R                    0x0008 
> > #define REG_BCRM_DEVICE_FIRMWARE_VERSION_R            0x0010
> > ^v4l2 regs
> 
> I'm not sure what you mean with "V4L2" registers ? I guess you mean
> registers which cannot be accessed through the CCI helper functions,
> but starting with v2 this is no longer true. There now is a CCI_REG64()
> so you can simply use that.

I'm playing a bit with v3 of your cci api :)

My problem is the following, bcrm regs are not real regs but are offset
from bcrm address (this is not fixed, it depends on the camera).

Then the workflow is:

 - read bcrm_address (base address)
 - then sum this to the offset (regs)

Myabe this clarify:

static int alvium_read(struct alvium_dev *alvium, u32 reg, u64 *val)
{
	int ret;

	if (reg & REG_BCRM_V4L2)
		reg += alvium->bcrm_addr;

	cci_read(alvium->regmap, reg, val, &ret);
	if (ret)
		return ret;

	return 0;
}

int alvium_write(struct alvium_dev *alvium, u32 reg, u64 val)
{
	int ret;

	if (reg & REG_BCRM_V4L2)
		reg += alvium->bcrm_addr;

	cci_write(alvium->regmap, reg, val, &ret);
	if (ret)
		return ret;

	return 0;
}

Where for example:

#define REG_BCRM_V4L2		BIT(31)
#define REG_BCRM_V4L2_64BIT(n)	(REG_BCRM_V4L2 | CCI_REG64(n))

#define REG_BCRM_WRITE_HANDSHAKE_RW REG_BCRM_V4L2_8BIT(0x0418)


But I'm not sure that I'm in the right direction. 

In real I need first to get the real address then sum the bcrm_address
if this is a bcrm regs(offset) then re-incapsule the address into the
right CCI_REG# defines.

Then I'm not completely sure that cci fits my use case.
What do you think about?

Btw really great work! :)

Thanks,
Tommaso



> 
> Regards,
> 
> Hans
> 
> 
> 
> > 
> > ?
> > 
> >>
> >>>
> >>> Note I'm about to send out a v3 addressing some small
> >>> remarks on this v2. I'll Cc you on that.
> >>
> >> Thanks, in this way I can test that and let you know my feedback.
> >>
> >> Regards,
> >> Tommaso
> >>
> >>>
> >>> Regards,
> >>>
> >>> Hans
> >>>
> >>>
> >>>>
> >>>> Let me know.
> >>>> Thanks! :)
> >>>>
> >>>> Regards,
> >>>> Tommaso
> >>>>
> >>>> On Thu, Jun 15, 2023 at 12:21:00PM +0300, Laurent Pinchart wrote:
> >>>>> On Thu, Jun 15, 2023 at 11:11:20AM +0200, Hans de Goede wrote:
> >>>>>> Hi Sakari,
> >>>>>>
> >>>>>> On 6/14/23 23:48, Sakari Ailus wrote:
> >>>>>>> Hi Laurent,
> >>>>>>>
> >>>>>>> On Thu, Jun 15, 2023 at 12:34:29AM +0300, Laurent Pinchart wrote:
> >>>>>>>> Hello,
> >>>>>>>>
> >>>>>>>> On Wed, Jun 14, 2023 at 08:39:56PM +0000, Sakari Ailus wrote:
> >>>>>>>>> On Wed, Jun 14, 2023 at 09:23:39PM +0200, Hans de Goede wrote:
> >>>>>>>>>> The CSI2 specification specifies a standard method to access camera sensor
> >>>>>>>>>> registers called "Camera Control Interface (CCI)".
> >>>>>>>>>>
> >>>>>>>>>> This uses either 8 or 16 bit (big-endian wire order) register addresses
> >>>>>>>>>> and supports 8, 16, 24 or 32 bit (big-endian wire order) register widths.
> >>>>>>>>>>
> >>>>>>>>>> Currently a lot of Linux camera sensor drivers all have their own custom
> >>>>>>>>>> helpers for this, often copy and pasted from other drivers.
> >>>>>>>>>>
> >>>>>>>>>> Add a set of generic helpers for this so that all sensor drivers can
> >>>>>>>>>> switch to a single common implementation.
> >>>>>>>>>>
> >>>>>>>>>> These helpers take an extra optional "int *err" function parameter,
> >>>>>>>>>> this can be used to chain a bunch of register accesses together with
> >>>>>>>>>> only a single error check at the end, rather then needing to error
> >>>>>>>>>> check each individual register access. The first failing call will
> >>>>>>>>>> set the contents of err to a non 0 value and all other calls will
> >>>>>>>>>> then become no-ops.
> >>>>>>>>>>
> >>>>>>>>>> Link: https://lore.kernel.org/linux-media/59aefa7f-7bf9-6736-6040-39551329cd0a@redhat.com/
> >>>>>>>>>> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
> >>>>>>>>>> ---
> >>>>>>>>>> Changes in v2:
> >>>>>>>>>> - Drop cci_reg_type enum
> >>>>>>>>>> - Make having an encoded reg-width mandatory rather then using 0 to encode
> >>>>>>>>>>   8 bit width making reg-addresses without an encoded width default to
> >>>>>>>>>>   a width of 8
> >>>>>>>>>> - Add support for 64 bit wide registers
> >>>>>>>>
> >>>>>>>> I'm in two minds about this. This means that the read and write
> >>>>>>>> functions take a u64 argument, which will be less efficient on 32-bit
> >>>>>>>> platforms. I think it would be possible, with some macro magic, to
> >>>>>>>> accept different argument sizes, but maybe that's a micro-optimization
> >>>>>>>> that would actually result in worse code. 
> >>>>>>>>
> >>>>>>>> 64-bit support could be useful, but as far as I can tell, it's not used
> >>>>>>>> in this series, so maybe we could leave this for later ?
> >>>>>>>
> >>>>>>> I prefer to have it now, I just told Tommaso working on the Alvium driver
> >>>>>>> to use this, and he needs 64-bit access. :-)
> >>>>>>>
> >>>>>>> You could also easily have 32-bit and 64-bit variant of the functions, with
> >>>>>>> C11 _Generic(). Introducing it now would be easier than later.
> >>>>>>
> >>>>>> I took a quick look at C11 _Generic() and that looks at the type
> >>>>>> of "things" so in this case it would look at type of the val argument.
> >>>>>>
> >>>>>> Problem is that that can still be e.g. an int when doing a
> >>>>>> read/write from a 64 bit registers.
> >>>>>>
> >>>>>> So we would then need to handle the 64 bit width case in the 32
> >>>>>> bit versions of the functions too.
> >>>>>>
> >>>>>> And likewise I can see someone passing a long on a 64 bit
> >>>>>> arch while doing a cci_write() to a non 64 bit register.
> >>>>>>
> >>>>>> So this would basically mean copy and pasting cci_read()
> >>>>>> + cci_write() 2x with the only difference being one
> >>>>>> variant taking a 32 bit val argument and the other a
> >>>>>> 64 bit val argument.
> >>>>>>
> >>>>>> This seems like premature optimization to me.
> >>>>>>
> >>>>>> As mentioned in my reply to Laurent if we want to
> >>>>>> optimize things we really should look at avoiding
> >>>>>> unnecessary i2c transfers, or packing multiple
> >>>>>> writes into a single i2c transfer for writes to
> >>>>>> subsequent registers. That is where significant
> >>>>>> speedups can be made.
> >>>>>
> >>>>> This is something I'd really like to see, but it's way more work.
> >>>>>
> >>>>> There's an important need of applying changes atomically, which is often
> >>>>> not possible to strictly guarantee over I2C. Userspace ends up writing
> >>>>> V4L2 controls as quickly as it can after the start of a frame, hoping
> >>>>> they will all reach the sensor before the end of the frame. Some
> >>>>> platforms have camera-specific I2C controllers that have the ability to
> >>>>> buffer I2C transfers and issue them based on a hardware trigger. How to
> >>>>> fit this in thé kernel I2C API will be an interesting exercise.
> >>>>>
> >>>>> -- 
> >>>>> Regards,
> >>>>>
> >>>>> Laurent Pinchart
> >>>>
> >>>
> > 
>
Laurent Pinchart June 15, 2023, 4:52 p.m. UTC | #28
Hi Tommaso,

On Thu, Jun 15, 2023 at 06:15:43PM +0200, Tommaso Merciai wrote:
> On Thu, Jun 15, 2023 at 02:00:46PM +0200, Hans de Goede wrote:
> > On 6/15/23 13:54, Tommaso Merciai wrote:
> > > On Thu, Jun 15, 2023 at 01:26:25PM +0200, Tommaso Merciai wrote:
> > >> On Thu, Jun 15, 2023 at 01:10:40PM +0200, Hans de Goede wrote:
> > >>> On 6/15/23 12:05, Tommaso Merciai wrote:
> > >>>> Hi Hans, Laurent, Sakari,
> > >>>>
> > >>>> Can I cherry-pick this patch and use these new functions also
> > >>>> for cci regs of the alvium driver?
> > >>>
> > >>> Yes that sounds like a good plan.
> > >>>
> > >>>> Are on going to be merge?
> > >>>
> > >>> Yes this will hopefully get merged upstream soon.
> > >>
> > >> Thanks for the info!
> > >>
> > >> I want to ask you your opinion about this:
> > >>
> > >> Into alvium driver actually I'm using the following defines
> > >> manipulations:
> > >>
> > >> #define REG_BCRM_REG_ADDR_R				REG_BCRM_CCI_16BIT(0x0014)
> > >>
> > >> #define REG_BCRM_FEATURE_INQUIRY_R			REG_BCRM_V4L2_64BIT(0x0008)
> > >> #define REG_BCRM_DEVICE_FIRMWARE_VERSION_R		REG_BCRM_V4L2_64BIT(0x0010)
> > >>
> > >> My plan is to use your cci API for cci register in this way defines
> > >> became like:
> > >>
> > >> #define REG_BCRM_REG_ADDR_R				CCI_REG16(0x0014)
> > >>
> > >> And leave v4l2 regs are it are right now:
> > >>
> > >> #define REG_BCRM_FEATURE_INQUIRY_R			REG_BCRM_V4L2_64BIT(0x0008)
> > >> #define REG_BCRM_DEVICE_FIRMWARE_VERSION_R		REG_BCRM_V4L2_64BIT(0x0010)
> > >>
> > >> What do you think about?
> > > 
> > > Or maybe is worth don't use v4l2 bit for v4l2 regs, I think is implicit
> > > that what regs that are not CCI are v4l2, then we return wit the
> > > following defines:
> > > 
> > > 
> > > 
> > > #define REG_BCRM_REG_ADDR_R                           CCI_REG16(0x0014)
> > > ^CCI regs
> > > 
> > > #define REG_BCRM_FEATURE_INQUIRY_R                    0x0008 
> > > #define REG_BCRM_DEVICE_FIRMWARE_VERSION_R            0x0010
> > > ^v4l2 regs
> > 
> > I'm not sure what you mean with "V4L2" registers ? I guess you mean
> > registers which cannot be accessed through the CCI helper functions,
> > but starting with v2 this is no longer true. There now is a CCI_REG64()
> > so you can simply use that.
> 
> I'm playing a bit with v3 of your cci api :)
> 
> My problem is the following, bcrm regs are not real regs but are offset
> from bcrm address (this is not fixed, it depends on the camera).
> 
> Then the workflow is:
> 
>  - read bcrm_address (base address)
>  - then sum this to the offset (regs)
> 
> Myabe this clarify:
> 
> static int alvium_read(struct alvium_dev *alvium, u32 reg, u64 *val)

I would add a int *err argument to your read and write wrappers.

> {
> 	int ret;
> 
> 	if (reg & REG_BCRM_V4L2)
> 		reg += alvium->bcrm_addr;
> 

You should also clear the REG_BCRM_V4L2 bit here:

 	if (reg & REG_BCRM_V4L2) {
		reg &= ~REG_BCRM_V4L2;
 		reg += alvium->bcrm_addr;
	}

> 	cci_read(alvium->regmap, reg, val, &ret);
> 	if (ret)
> 		return ret;
> 
> 	return 0;

Just

	return cci_read(alvium->regmap, reg, val, err);

Same for alvium_write()..

> }
> 
> int alvium_write(struct alvium_dev *alvium, u32 reg, u64 val)
> {
> 	int ret;
> 
> 	if (reg & REG_BCRM_V4L2)
> 		reg += alvium->bcrm_addr;
> 
> 	cci_write(alvium->regmap, reg, val, &ret);
> 	if (ret)
> 		return ret;
> 
> 	return 0;
> }
> 
> Where for example:
> 
> #define REG_BCRM_V4L2		BIT(31)
> #define REG_BCRM_V4L2_64BIT(n)	(REG_BCRM_V4L2 | CCI_REG64(n))
> 
> #define REG_BCRM_WRITE_HANDSHAKE_RW REG_BCRM_V4L2_8BIT(0x0418)
> 
> 
> But I'm not sure that I'm in the right direction. 

This looks good to me.

The fact that both Hans' helpers and part of the Alvium camera registers
are named CCI is not a complete coincidence, but it doesn't mean they're
identical. I would thus keep the REG_BCRM_CCI_* macros for clarity,
simply defining them as CCI_* wrappers:

#define REG_BCRM_V4L2_8BIT(n)		CCI_REG8(n)
...

> In real I need first to get the real address then sum the bcrm_address
> if this is a bcrm regs(offset) then re-incapsule the address into the
> right CCI_REG# defines.
> 
> Then I'm not completely sure that cci fits my use case.
> What do you think about?
> 
> Btw really great work! :)
> 
> > > ?
> > > 
> > >>> Note I'm about to send out a v3 addressing some small
> > >>> remarks on this v2. I'll Cc you on that.
> > >>
> > >> Thanks, in this way I can test that and let you know my feedback.
> > >>
> > >>>> Let me know.
> > >>>> Thanks! :)
> > >>>>
> > >>>> On Thu, Jun 15, 2023 at 12:21:00PM +0300, Laurent Pinchart wrote:
> > >>>>> On Thu, Jun 15, 2023 at 11:11:20AM +0200, Hans de Goede wrote:
> > >>>>>> On 6/14/23 23:48, Sakari Ailus wrote:
> > >>>>>>> On Thu, Jun 15, 2023 at 12:34:29AM +0300, Laurent Pinchart wrote:
> > >>>>>>>> On Wed, Jun 14, 2023 at 08:39:56PM +0000, Sakari Ailus wrote:
> > >>>>>>>>> On Wed, Jun 14, 2023 at 09:23:39PM +0200, Hans de Goede wrote:
> > >>>>>>>>>> The CSI2 specification specifies a standard method to access camera sensor
> > >>>>>>>>>> registers called "Camera Control Interface (CCI)".
> > >>>>>>>>>>
> > >>>>>>>>>> This uses either 8 or 16 bit (big-endian wire order) register addresses
> > >>>>>>>>>> and supports 8, 16, 24 or 32 bit (big-endian wire order) register widths.
> > >>>>>>>>>>
> > >>>>>>>>>> Currently a lot of Linux camera sensor drivers all have their own custom
> > >>>>>>>>>> helpers for this, often copy and pasted from other drivers.
> > >>>>>>>>>>
> > >>>>>>>>>> Add a set of generic helpers for this so that all sensor drivers can
> > >>>>>>>>>> switch to a single common implementation.
> > >>>>>>>>>>
> > >>>>>>>>>> These helpers take an extra optional "int *err" function parameter,
> > >>>>>>>>>> this can be used to chain a bunch of register accesses together with
> > >>>>>>>>>> only a single error check at the end, rather then needing to error
> > >>>>>>>>>> check each individual register access. The first failing call will
> > >>>>>>>>>> set the contents of err to a non 0 value and all other calls will
> > >>>>>>>>>> then become no-ops.
> > >>>>>>>>>>
> > >>>>>>>>>> Link: https://lore.kernel.org/linux-media/59aefa7f-7bf9-6736-6040-39551329cd0a@redhat.com/
> > >>>>>>>>>> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
> > >>>>>>>>>> ---
> > >>>>>>>>>> Changes in v2:
> > >>>>>>>>>> - Drop cci_reg_type enum
> > >>>>>>>>>> - Make having an encoded reg-width mandatory rather then using 0 to encode
> > >>>>>>>>>>   8 bit width making reg-addresses without an encoded width default to
> > >>>>>>>>>>   a width of 8
> > >>>>>>>>>> - Add support for 64 bit wide registers
> > >>>>>>>>
> > >>>>>>>> I'm in two minds about this. This means that the read and write
> > >>>>>>>> functions take a u64 argument, which will be less efficient on 32-bit
> > >>>>>>>> platforms. I think it would be possible, with some macro magic, to
> > >>>>>>>> accept different argument sizes, but maybe that's a micro-optimization
> > >>>>>>>> that would actually result in worse code. 
> > >>>>>>>>
> > >>>>>>>> 64-bit support could be useful, but as far as I can tell, it's not used
> > >>>>>>>> in this series, so maybe we could leave this for later ?
> > >>>>>>>
> > >>>>>>> I prefer to have it now, I just told Tommaso working on the Alvium driver
> > >>>>>>> to use this, and he needs 64-bit access. :-)
> > >>>>>>>
> > >>>>>>> You could also easily have 32-bit and 64-bit variant of the functions, with
> > >>>>>>> C11 _Generic(). Introducing it now would be easier than later.
> > >>>>>>
> > >>>>>> I took a quick look at C11 _Generic() and that looks at the type
> > >>>>>> of "things" so in this case it would look at type of the val argument.
> > >>>>>>
> > >>>>>> Problem is that that can still be e.g. an int when doing a
> > >>>>>> read/write from a 64 bit registers.
> > >>>>>>
> > >>>>>> So we would then need to handle the 64 bit width case in the 32
> > >>>>>> bit versions of the functions too.
> > >>>>>>
> > >>>>>> And likewise I can see someone passing a long on a 64 bit
> > >>>>>> arch while doing a cci_write() to a non 64 bit register.
> > >>>>>>
> > >>>>>> So this would basically mean copy and pasting cci_read()
> > >>>>>> + cci_write() 2x with the only difference being one
> > >>>>>> variant taking a 32 bit val argument and the other a
> > >>>>>> 64 bit val argument.
> > >>>>>>
> > >>>>>> This seems like premature optimization to me.
> > >>>>>>
> > >>>>>> As mentioned in my reply to Laurent if we want to
> > >>>>>> optimize things we really should look at avoiding
> > >>>>>> unnecessary i2c transfers, or packing multiple
> > >>>>>> writes into a single i2c transfer for writes to
> > >>>>>> subsequent registers. That is where significant
> > >>>>>> speedups can be made.
> > >>>>>
> > >>>>> This is something I'd really like to see, but it's way more work.
> > >>>>>
> > >>>>> There's an important need of applying changes atomically, which is often
> > >>>>> not possible to strictly guarantee over I2C. Userspace ends up writing
> > >>>>> V4L2 controls as quickly as it can after the start of a frame, hoping
> > >>>>> they will all reach the sensor before the end of the frame. Some
> > >>>>> platforms have camera-specific I2C controllers that have the ability to
> > >>>>> buffer I2C transfers and issue them based on a hardware trigger. How to
> > >>>>> fit this in thé kernel I2C API will be an interesting exercise.
Tommaso Merciai June 15, 2023, 10:20 p.m. UTC | #29
Hi Laurent,

On Thu, Jun 15, 2023 at 07:52:36PM +0300, Laurent Pinchart wrote:
> Hi Tommaso,
> 
> On Thu, Jun 15, 2023 at 06:15:43PM +0200, Tommaso Merciai wrote:
> > On Thu, Jun 15, 2023 at 02:00:46PM +0200, Hans de Goede wrote:
> > > On 6/15/23 13:54, Tommaso Merciai wrote:
> > > > On Thu, Jun 15, 2023 at 01:26:25PM +0200, Tommaso Merciai wrote:
> > > >> On Thu, Jun 15, 2023 at 01:10:40PM +0200, Hans de Goede wrote:
> > > >>> On 6/15/23 12:05, Tommaso Merciai wrote:
> > > >>>> Hi Hans, Laurent, Sakari,
> > > >>>>
> > > >>>> Can I cherry-pick this patch and use these new functions also
> > > >>>> for cci regs of the alvium driver?
> > > >>>
> > > >>> Yes that sounds like a good plan.
> > > >>>
> > > >>>> Are on going to be merge?
> > > >>>
> > > >>> Yes this will hopefully get merged upstream soon.
> > > >>
> > > >> Thanks for the info!
> > > >>
> > > >> I want to ask you your opinion about this:
> > > >>
> > > >> Into alvium driver actually I'm using the following defines
> > > >> manipulations:
> > > >>
> > > >> #define REG_BCRM_REG_ADDR_R				REG_BCRM_CCI_16BIT(0x0014)
> > > >>
> > > >> #define REG_BCRM_FEATURE_INQUIRY_R			REG_BCRM_V4L2_64BIT(0x0008)
> > > >> #define REG_BCRM_DEVICE_FIRMWARE_VERSION_R		REG_BCRM_V4L2_64BIT(0x0010)
> > > >>
> > > >> My plan is to use your cci API for cci register in this way defines
> > > >> became like:
> > > >>
> > > >> #define REG_BCRM_REG_ADDR_R				CCI_REG16(0x0014)
> > > >>
> > > >> And leave v4l2 regs are it are right now:
> > > >>
> > > >> #define REG_BCRM_FEATURE_INQUIRY_R			REG_BCRM_V4L2_64BIT(0x0008)
> > > >> #define REG_BCRM_DEVICE_FIRMWARE_VERSION_R		REG_BCRM_V4L2_64BIT(0x0010)
> > > >>
> > > >> What do you think about?
> > > > 
> > > > Or maybe is worth don't use v4l2 bit for v4l2 regs, I think is implicit
> > > > that what regs that are not CCI are v4l2, then we return wit the
> > > > following defines:
> > > > 
> > > > 
> > > > 
> > > > #define REG_BCRM_REG_ADDR_R                           CCI_REG16(0x0014)
> > > > ^CCI regs
> > > > 
> > > > #define REG_BCRM_FEATURE_INQUIRY_R                    0x0008 
> > > > #define REG_BCRM_DEVICE_FIRMWARE_VERSION_R            0x0010
> > > > ^v4l2 regs
> > > 
> > > I'm not sure what you mean with "V4L2" registers ? I guess you mean
> > > registers which cannot be accessed through the CCI helper functions,
> > > but starting with v2 this is no longer true. There now is a CCI_REG64()
> > > so you can simply use that.
> > 
> > I'm playing a bit with v3 of your cci api :)
> > 
> > My problem is the following, bcrm regs are not real regs but are offset
> > from bcrm address (this is not fixed, it depends on the camera).
> > 
> > Then the workflow is:
> > 
> >  - read bcrm_address (base address)
> >  - then sum this to the offset (regs)
> > 
> > Myabe this clarify:
> > 
> > static int alvium_read(struct alvium_dev *alvium, u32 reg, u64 *val)
> 
> I would add a int *err argument to your read and write wrappers.


Thanks for your hint!
What about using:

static int alvium_write(struct alvium_dev *alvium, u32 reg, u64 val)
{
	if (reg & REG_BCRM_V4L2) {
		reg &= ~REG_BCRM_V4L2;
		reg += alvium->bcrm_addr;
	}

	return cci_write(alvium->regmap, reg, val, NULL);
}

Then:

	ret = alvium_write(alvium, reg, val);
	if (ret) {
		dev_err(dev, "Fail to write reg\n");
		return ret;
	}


I prefer to use this format if for you is ok.
Let me know.

Thanks again!

Regards,
Tommaso

> 
> > {
> > 	int ret;
> > 
> > 	if (reg & REG_BCRM_V4L2)
> > 		reg += alvium->bcrm_addr;
> > 
> 
> You should also clear the REG_BCRM_V4L2 bit here:
> 
>  	if (reg & REG_BCRM_V4L2) {
> 		reg &= ~REG_BCRM_V4L2;
>  		reg += alvium->bcrm_addr;
> 	}
> 
> > 	cci_read(alvium->regmap, reg, val, &ret);
> > 	if (ret)
> > 		return ret;
> > 
> > 	return 0;
> 
> Just
> 
> 	return cci_read(alvium->regmap, reg, val, err);
> 
> Same for alvium_write()..
> 
> > }
> > 
> > int alvium_write(struct alvium_dev *alvium, u32 reg, u64 val)
> > {
> > 	int ret;
> > 
> > 	if (reg & REG_BCRM_V4L2)
> > 		reg += alvium->bcrm_addr;
> > 
> > 	cci_write(alvium->regmap, reg, val, &ret);
> > 	if (ret)
> > 		return ret;
> > 
> > 	return 0;
> > }
> > 
> > Where for example:
> > 
> > #define REG_BCRM_V4L2		BIT(31)
> > #define REG_BCRM_V4L2_64BIT(n)	(REG_BCRM_V4L2 | CCI_REG64(n))
> > 
> > #define REG_BCRM_WRITE_HANDSHAKE_RW REG_BCRM_V4L2_8BIT(0x0418)
> > 
> > 
> > But I'm not sure that I'm in the right direction. 
> 
> This looks good to me.
> 
> The fact that both Hans' helpers and part of the Alvium camera registers
> are named CCI is not a complete coincidence, but it doesn't mean they're
> identical. I would thus keep the REG_BCRM_CCI_* macros for clarity,
> simply defining them as CCI_* wrappers:
> 
> #define REG_BCRM_V4L2_8BIT(n)		CCI_REG8(n)
> ...
> 
> > In real I need first to get the real address then sum the bcrm_address
> > if this is a bcrm regs(offset) then re-incapsule the address into the
> > right CCI_REG# defines.
> > 
> > Then I'm not completely sure that cci fits my use case.
> > What do you think about?
> > 
> > Btw really great work! :)
> > 
> > > > ?
> > > > 
> > > >>> Note I'm about to send out a v3 addressing some small
> > > >>> remarks on this v2. I'll Cc you on that.
> > > >>
> > > >> Thanks, in this way I can test that and let you know my feedback.
> > > >>
> > > >>>> Let me know.
> > > >>>> Thanks! :)
> > > >>>>
> > > >>>> On Thu, Jun 15, 2023 at 12:21:00PM +0300, Laurent Pinchart wrote:
> > > >>>>> On Thu, Jun 15, 2023 at 11:11:20AM +0200, Hans de Goede wrote:
> > > >>>>>> On 6/14/23 23:48, Sakari Ailus wrote:
> > > >>>>>>> On Thu, Jun 15, 2023 at 12:34:29AM +0300, Laurent Pinchart wrote:
> > > >>>>>>>> On Wed, Jun 14, 2023 at 08:39:56PM +0000, Sakari Ailus wrote:
> > > >>>>>>>>> On Wed, Jun 14, 2023 at 09:23:39PM +0200, Hans de Goede wrote:
> > > >>>>>>>>>> The CSI2 specification specifies a standard method to access camera sensor
> > > >>>>>>>>>> registers called "Camera Control Interface (CCI)".
> > > >>>>>>>>>>
> > > >>>>>>>>>> This uses either 8 or 16 bit (big-endian wire order) register addresses
> > > >>>>>>>>>> and supports 8, 16, 24 or 32 bit (big-endian wire order) register widths.
> > > >>>>>>>>>>
> > > >>>>>>>>>> Currently a lot of Linux camera sensor drivers all have their own custom
> > > >>>>>>>>>> helpers for this, often copy and pasted from other drivers.
> > > >>>>>>>>>>
> > > >>>>>>>>>> Add a set of generic helpers for this so that all sensor drivers can
> > > >>>>>>>>>> switch to a single common implementation.
> > > >>>>>>>>>>
> > > >>>>>>>>>> These helpers take an extra optional "int *err" function parameter,
> > > >>>>>>>>>> this can be used to chain a bunch of register accesses together with
> > > >>>>>>>>>> only a single error check at the end, rather then needing to error
> > > >>>>>>>>>> check each individual register access. The first failing call will
> > > >>>>>>>>>> set the contents of err to a non 0 value and all other calls will
> > > >>>>>>>>>> then become no-ops.
> > > >>>>>>>>>>
> > > >>>>>>>>>> Link: https://lore.kernel.org/linux-media/59aefa7f-7bf9-6736-6040-39551329cd0a@redhat.com/
> > > >>>>>>>>>> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
> > > >>>>>>>>>> ---
> > > >>>>>>>>>> Changes in v2:
> > > >>>>>>>>>> - Drop cci_reg_type enum
> > > >>>>>>>>>> - Make having an encoded reg-width mandatory rather then using 0 to encode
> > > >>>>>>>>>>   8 bit width making reg-addresses without an encoded width default to
> > > >>>>>>>>>>   a width of 8
> > > >>>>>>>>>> - Add support for 64 bit wide registers
> > > >>>>>>>>
> > > >>>>>>>> I'm in two minds about this. This means that the read and write
> > > >>>>>>>> functions take a u64 argument, which will be less efficient on 32-bit
> > > >>>>>>>> platforms. I think it would be possible, with some macro magic, to
> > > >>>>>>>> accept different argument sizes, but maybe that's a micro-optimization
> > > >>>>>>>> that would actually result in worse code. 
> > > >>>>>>>>
> > > >>>>>>>> 64-bit support could be useful, but as far as I can tell, it's not used
> > > >>>>>>>> in this series, so maybe we could leave this for later ?
> > > >>>>>>>
> > > >>>>>>> I prefer to have it now, I just told Tommaso working on the Alvium driver
> > > >>>>>>> to use this, and he needs 64-bit access. :-)
> > > >>>>>>>
> > > >>>>>>> You could also easily have 32-bit and 64-bit variant of the functions, with
> > > >>>>>>> C11 _Generic(). Introducing it now would be easier than later.
> > > >>>>>>
> > > >>>>>> I took a quick look at C11 _Generic() and that looks at the type
> > > >>>>>> of "things" so in this case it would look at type of the val argument.
> > > >>>>>>
> > > >>>>>> Problem is that that can still be e.g. an int when doing a
> > > >>>>>> read/write from a 64 bit registers.
> > > >>>>>>
> > > >>>>>> So we would then need to handle the 64 bit width case in the 32
> > > >>>>>> bit versions of the functions too.
> > > >>>>>>
> > > >>>>>> And likewise I can see someone passing a long on a 64 bit
> > > >>>>>> arch while doing a cci_write() to a non 64 bit register.
> > > >>>>>>
> > > >>>>>> So this would basically mean copy and pasting cci_read()
> > > >>>>>> + cci_write() 2x with the only difference being one
> > > >>>>>> variant taking a 32 bit val argument and the other a
> > > >>>>>> 64 bit val argument.
> > > >>>>>>
> > > >>>>>> This seems like premature optimization to me.
> > > >>>>>>
> > > >>>>>> As mentioned in my reply to Laurent if we want to
> > > >>>>>> optimize things we really should look at avoiding
> > > >>>>>> unnecessary i2c transfers, or packing multiple
> > > >>>>>> writes into a single i2c transfer for writes to
> > > >>>>>> subsequent registers. That is where significant
> > > >>>>>> speedups can be made.
> > > >>>>>
> > > >>>>> This is something I'd really like to see, but it's way more work.
> > > >>>>>
> > > >>>>> There's an important need of applying changes atomically, which is often
> > > >>>>> not possible to strictly guarantee over I2C. Userspace ends up writing
> > > >>>>> V4L2 controls as quickly as it can after the start of a frame, hoping
> > > >>>>> they will all reach the sensor before the end of the frame. Some
> > > >>>>> platforms have camera-specific I2C controllers that have the ability to
> > > >>>>> buffer I2C transfers and issue them based on a hardware trigger. How to
> > > >>>>> fit this in thé kernel I2C API will be an interesting exercise.
> 
> -- 
> Regards,
> 
> Laurent Pinchart
Laurent Pinchart June 16, 2023, 1:41 p.m. UTC | #30
Hi Tommaso,

On Fri, Jun 16, 2023 at 12:20:16AM +0200, Tommaso Merciai wrote:
> On Thu, Jun 15, 2023 at 07:52:36PM +0300, Laurent Pinchart wrote:
> > On Thu, Jun 15, 2023 at 06:15:43PM +0200, Tommaso Merciai wrote:
> > > On Thu, Jun 15, 2023 at 02:00:46PM +0200, Hans de Goede wrote:
> > > > On 6/15/23 13:54, Tommaso Merciai wrote:
> > > > > On Thu, Jun 15, 2023 at 01:26:25PM +0200, Tommaso Merciai wrote:
> > > > >> On Thu, Jun 15, 2023 at 01:10:40PM +0200, Hans de Goede wrote:
> > > > >>> On 6/15/23 12:05, Tommaso Merciai wrote:
> > > > >>>> Hi Hans, Laurent, Sakari,
> > > > >>>>
> > > > >>>> Can I cherry-pick this patch and use these new functions also
> > > > >>>> for cci regs of the alvium driver?
> > > > >>>
> > > > >>> Yes that sounds like a good plan.
> > > > >>>
> > > > >>>> Are on going to be merge?
> > > > >>>
> > > > >>> Yes this will hopefully get merged upstream soon.
> > > > >>
> > > > >> Thanks for the info!
> > > > >>
> > > > >> I want to ask you your opinion about this:
> > > > >>
> > > > >> Into alvium driver actually I'm using the following defines
> > > > >> manipulations:
> > > > >>
> > > > >> #define REG_BCRM_REG_ADDR_R				REG_BCRM_CCI_16BIT(0x0014)
> > > > >>
> > > > >> #define REG_BCRM_FEATURE_INQUIRY_R			REG_BCRM_V4L2_64BIT(0x0008)
> > > > >> #define REG_BCRM_DEVICE_FIRMWARE_VERSION_R		REG_BCRM_V4L2_64BIT(0x0010)
> > > > >>
> > > > >> My plan is to use your cci API for cci register in this way defines
> > > > >> became like:
> > > > >>
> > > > >> #define REG_BCRM_REG_ADDR_R				CCI_REG16(0x0014)
> > > > >>
> > > > >> And leave v4l2 regs are it are right now:
> > > > >>
> > > > >> #define REG_BCRM_FEATURE_INQUIRY_R			REG_BCRM_V4L2_64BIT(0x0008)
> > > > >> #define REG_BCRM_DEVICE_FIRMWARE_VERSION_R		REG_BCRM_V4L2_64BIT(0x0010)
> > > > >>
> > > > >> What do you think about?
> > > > > 
> > > > > Or maybe is worth don't use v4l2 bit for v4l2 regs, I think is implicit
> > > > > that what regs that are not CCI are v4l2, then we return wit the
> > > > > following defines:
> > > > > 
> > > > > 
> > > > > 
> > > > > #define REG_BCRM_REG_ADDR_R                           CCI_REG16(0x0014)
> > > > > ^CCI regs
> > > > > 
> > > > > #define REG_BCRM_FEATURE_INQUIRY_R                    0x0008 
> > > > > #define REG_BCRM_DEVICE_FIRMWARE_VERSION_R            0x0010
> > > > > ^v4l2 regs
> > > > 
> > > > I'm not sure what you mean with "V4L2" registers ? I guess you mean
> > > > registers which cannot be accessed through the CCI helper functions,
> > > > but starting with v2 this is no longer true. There now is a CCI_REG64()
> > > > so you can simply use that.
> > > 
> > > I'm playing a bit with v3 of your cci api :)
> > > 
> > > My problem is the following, bcrm regs are not real regs but are offset
> > > from bcrm address (this is not fixed, it depends on the camera).
> > > 
> > > Then the workflow is:
> > > 
> > >  - read bcrm_address (base address)
> > >  - then sum this to the offset (regs)
> > > 
> > > Myabe this clarify:
> > > 
> > > static int alvium_read(struct alvium_dev *alvium, u32 reg, u64 *val)
> > 
> > I would add a int *err argument to your read and write wrappers.
> 
> 
> Thanks for your hint!
> What about using:
> 
> static int alvium_write(struct alvium_dev *alvium, u32 reg, u64 val)
> {
> 	if (reg & REG_BCRM_V4L2) {
> 		reg &= ~REG_BCRM_V4L2;
> 		reg += alvium->bcrm_addr;
> 	}
> 
> 	return cci_write(alvium->regmap, reg, val, NULL);
> }
> 
> Then:
> 
> 	ret = alvium_write(alvium, reg, val);
> 	if (ret) {
> 		dev_err(dev, "Fail to write reg\n");
> 		return ret;
> 	}
> 
> 
> I prefer to use this format if for you is ok.
> Let me know.

This is fine when you have to write a single register only, but it makes
things more complicated when writing multiple registers. Consider this:

	int ret;

	ret = alvium_write(alvium, REG_A, val);
	if (ret)
		return ret;

	ret = alvium_write(alvium, REG_B, val);
	if (ret)
		return ret;

	ret = alvium_write(alvium, REG_C, val);
	if (ret)
		return ret;

	ret = alvium_write(alvium, REG_D, val);
	if (ret)
		return ret;

	return 0;

and compare it to

	int ret = 0;

	alvium_write(alvium, REG_A, val, &ret);
	alvium_write(alvium, REG_B, val, &ret);
	alvium_write(alvium, REG_C, val, &ret);
	alvium_write(alvium, REG_D, val, &ret);

	return ret;

> > > {
> > > 	int ret;
> > > 
> > > 	if (reg & REG_BCRM_V4L2)
> > > 		reg += alvium->bcrm_addr;
> > > 
> > 
> > You should also clear the REG_BCRM_V4L2 bit here:
> > 
> >  	if (reg & REG_BCRM_V4L2) {
> > 		reg &= ~REG_BCRM_V4L2;
> >  		reg += alvium->bcrm_addr;
> > 	}
> > 
> > > 	cci_read(alvium->regmap, reg, val, &ret);
> > > 	if (ret)
> > > 		return ret;
> > > 
> > > 	return 0;
> > 
> > Just
> > 
> > 	return cci_read(alvium->regmap, reg, val, err);
> > 
> > Same for alvium_write()..
> > 
> > > }
> > > 
> > > int alvium_write(struct alvium_dev *alvium, u32 reg, u64 val)
> > > {
> > > 	int ret;
> > > 
> > > 	if (reg & REG_BCRM_V4L2)
> > > 		reg += alvium->bcrm_addr;
> > > 
> > > 	cci_write(alvium->regmap, reg, val, &ret);
> > > 	if (ret)
> > > 		return ret;
> > > 
> > > 	return 0;
> > > }
> > > 
> > > Where for example:
> > > 
> > > #define REG_BCRM_V4L2		BIT(31)
> > > #define REG_BCRM_V4L2_64BIT(n)	(REG_BCRM_V4L2 | CCI_REG64(n))
> > > 
> > > #define REG_BCRM_WRITE_HANDSHAKE_RW REG_BCRM_V4L2_8BIT(0x0418)
> > > 
> > > 
> > > But I'm not sure that I'm in the right direction. 
> > 
> > This looks good to me.
> > 
> > The fact that both Hans' helpers and part of the Alvium camera registers
> > are named CCI is not a complete coincidence, but it doesn't mean they're
> > identical. I would thus keep the REG_BCRM_CCI_* macros for clarity,
> > simply defining them as CCI_* wrappers:
> > 
> > #define REG_BCRM_V4L2_8BIT(n)		CCI_REG8(n)
> > ...
> > 
> > > In real I need first to get the real address then sum the bcrm_address
> > > if this is a bcrm regs(offset) then re-incapsule the address into the
> > > right CCI_REG# defines.
> > > 
> > > Then I'm not completely sure that cci fits my use case.
> > > What do you think about?
> > > 
> > > Btw really great work! :)
> > > 
> > > > > ?
> > > > > 
> > > > >>> Note I'm about to send out a v3 addressing some small
> > > > >>> remarks on this v2. I'll Cc you on that.
> > > > >>
> > > > >> Thanks, in this way I can test that and let you know my feedback.
> > > > >>
> > > > >>>> Let me know.
> > > > >>>> Thanks! :)
> > > > >>>>
> > > > >>>> On Thu, Jun 15, 2023 at 12:21:00PM +0300, Laurent Pinchart wrote:
> > > > >>>>> On Thu, Jun 15, 2023 at 11:11:20AM +0200, Hans de Goede wrote:
> > > > >>>>>> On 6/14/23 23:48, Sakari Ailus wrote:
> > > > >>>>>>> On Thu, Jun 15, 2023 at 12:34:29AM +0300, Laurent Pinchart wrote:
> > > > >>>>>>>> On Wed, Jun 14, 2023 at 08:39:56PM +0000, Sakari Ailus wrote:
> > > > >>>>>>>>> On Wed, Jun 14, 2023 at 09:23:39PM +0200, Hans de Goede wrote:
> > > > >>>>>>>>>> The CSI2 specification specifies a standard method to access camera sensor
> > > > >>>>>>>>>> registers called "Camera Control Interface (CCI)".
> > > > >>>>>>>>>>
> > > > >>>>>>>>>> This uses either 8 or 16 bit (big-endian wire order) register addresses
> > > > >>>>>>>>>> and supports 8, 16, 24 or 32 bit (big-endian wire order) register widths.
> > > > >>>>>>>>>>
> > > > >>>>>>>>>> Currently a lot of Linux camera sensor drivers all have their own custom
> > > > >>>>>>>>>> helpers for this, often copy and pasted from other drivers.
> > > > >>>>>>>>>>
> > > > >>>>>>>>>> Add a set of generic helpers for this so that all sensor drivers can
> > > > >>>>>>>>>> switch to a single common implementation.
> > > > >>>>>>>>>>
> > > > >>>>>>>>>> These helpers take an extra optional "int *err" function parameter,
> > > > >>>>>>>>>> this can be used to chain a bunch of register accesses together with
> > > > >>>>>>>>>> only a single error check at the end, rather then needing to error
> > > > >>>>>>>>>> check each individual register access. The first failing call will
> > > > >>>>>>>>>> set the contents of err to a non 0 value and all other calls will
> > > > >>>>>>>>>> then become no-ops.
> > > > >>>>>>>>>>
> > > > >>>>>>>>>> Link: https://lore.kernel.org/linux-media/59aefa7f-7bf9-6736-6040-39551329cd0a@redhat.com/
> > > > >>>>>>>>>> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
> > > > >>>>>>>>>> ---
> > > > >>>>>>>>>> Changes in v2:
> > > > >>>>>>>>>> - Drop cci_reg_type enum
> > > > >>>>>>>>>> - Make having an encoded reg-width mandatory rather then using 0 to encode
> > > > >>>>>>>>>>   8 bit width making reg-addresses without an encoded width default to
> > > > >>>>>>>>>>   a width of 8
> > > > >>>>>>>>>> - Add support for 64 bit wide registers
> > > > >>>>>>>>
> > > > >>>>>>>> I'm in two minds about this. This means that the read and write
> > > > >>>>>>>> functions take a u64 argument, which will be less efficient on 32-bit
> > > > >>>>>>>> platforms. I think it would be possible, with some macro magic, to
> > > > >>>>>>>> accept different argument sizes, but maybe that's a micro-optimization
> > > > >>>>>>>> that would actually result in worse code. 
> > > > >>>>>>>>
> > > > >>>>>>>> 64-bit support could be useful, but as far as I can tell, it's not used
> > > > >>>>>>>> in this series, so maybe we could leave this for later ?
> > > > >>>>>>>
> > > > >>>>>>> I prefer to have it now, I just told Tommaso working on the Alvium driver
> > > > >>>>>>> to use this, and he needs 64-bit access. :-)
> > > > >>>>>>>
> > > > >>>>>>> You could also easily have 32-bit and 64-bit variant of the functions, with
> > > > >>>>>>> C11 _Generic(). Introducing it now would be easier than later.
> > > > >>>>>>
> > > > >>>>>> I took a quick look at C11 _Generic() and that looks at the type
> > > > >>>>>> of "things" so in this case it would look at type of the val argument.
> > > > >>>>>>
> > > > >>>>>> Problem is that that can still be e.g. an int when doing a
> > > > >>>>>> read/write from a 64 bit registers.
> > > > >>>>>>
> > > > >>>>>> So we would then need to handle the 64 bit width case in the 32
> > > > >>>>>> bit versions of the functions too.
> > > > >>>>>>
> > > > >>>>>> And likewise I can see someone passing a long on a 64 bit
> > > > >>>>>> arch while doing a cci_write() to a non 64 bit register.
> > > > >>>>>>
> > > > >>>>>> So this would basically mean copy and pasting cci_read()
> > > > >>>>>> + cci_write() 2x with the only difference being one
> > > > >>>>>> variant taking a 32 bit val argument and the other a
> > > > >>>>>> 64 bit val argument.
> > > > >>>>>>
> > > > >>>>>> This seems like premature optimization to me.
> > > > >>>>>>
> > > > >>>>>> As mentioned in my reply to Laurent if we want to
> > > > >>>>>> optimize things we really should look at avoiding
> > > > >>>>>> unnecessary i2c transfers, or packing multiple
> > > > >>>>>> writes into a single i2c transfer for writes to
> > > > >>>>>> subsequent registers. That is where significant
> > > > >>>>>> speedups can be made.
> > > > >>>>>
> > > > >>>>> This is something I'd really like to see, but it's way more work.
> > > > >>>>>
> > > > >>>>> There's an important need of applying changes atomically, which is often
> > > > >>>>> not possible to strictly guarantee over I2C. Userspace ends up writing
> > > > >>>>> V4L2 controls as quickly as it can after the start of a frame, hoping
> > > > >>>>> they will all reach the sensor before the end of the frame. Some
> > > > >>>>> platforms have camera-specific I2C controllers that have the ability to
> > > > >>>>> buffer I2C transfers and issue them based on a hardware trigger. How to
> > > > >>>>> fit this in thé kernel I2C API will be an interesting exercise.
Tommaso Merciai June 16, 2023, 2:08 p.m. UTC | #31
Hi Laurent,
Thanks for your time.

On Fri, Jun 16, 2023 at 04:41:24PM +0300, Laurent Pinchart wrote:
> Hi Tommaso,
> 
> On Fri, Jun 16, 2023 at 12:20:16AM +0200, Tommaso Merciai wrote:
> > On Thu, Jun 15, 2023 at 07:52:36PM +0300, Laurent Pinchart wrote:
> > > On Thu, Jun 15, 2023 at 06:15:43PM +0200, Tommaso Merciai wrote:
> > > > On Thu, Jun 15, 2023 at 02:00:46PM +0200, Hans de Goede wrote:
> > > > > On 6/15/23 13:54, Tommaso Merciai wrote:
> > > > > > On Thu, Jun 15, 2023 at 01:26:25PM +0200, Tommaso Merciai wrote:
> > > > > >> On Thu, Jun 15, 2023 at 01:10:40PM +0200, Hans de Goede wrote:
> > > > > >>> On 6/15/23 12:05, Tommaso Merciai wrote:
> > > > > >>>> Hi Hans, Laurent, Sakari,
> > > > > >>>>
> > > > > >>>> Can I cherry-pick this patch and use these new functions also
> > > > > >>>> for cci regs of the alvium driver?
> > > > > >>>
> > > > > >>> Yes that sounds like a good plan.
> > > > > >>>
> > > > > >>>> Are on going to be merge?
> > > > > >>>
> > > > > >>> Yes this will hopefully get merged upstream soon.
> > > > > >>
> > > > > >> Thanks for the info!
> > > > > >>
> > > > > >> I want to ask you your opinion about this:
> > > > > >>
> > > > > >> Into alvium driver actually I'm using the following defines
> > > > > >> manipulations:
> > > > > >>
> > > > > >> #define REG_BCRM_REG_ADDR_R				REG_BCRM_CCI_16BIT(0x0014)
> > > > > >>
> > > > > >> #define REG_BCRM_FEATURE_INQUIRY_R			REG_BCRM_V4L2_64BIT(0x0008)
> > > > > >> #define REG_BCRM_DEVICE_FIRMWARE_VERSION_R		REG_BCRM_V4L2_64BIT(0x0010)
> > > > > >>
> > > > > >> My plan is to use your cci API for cci register in this way defines
> > > > > >> became like:
> > > > > >>
> > > > > >> #define REG_BCRM_REG_ADDR_R				CCI_REG16(0x0014)
> > > > > >>
> > > > > >> And leave v4l2 regs are it are right now:
> > > > > >>
> > > > > >> #define REG_BCRM_FEATURE_INQUIRY_R			REG_BCRM_V4L2_64BIT(0x0008)
> > > > > >> #define REG_BCRM_DEVICE_FIRMWARE_VERSION_R		REG_BCRM_V4L2_64BIT(0x0010)
> > > > > >>
> > > > > >> What do you think about?
> > > > > > 
> > > > > > Or maybe is worth don't use v4l2 bit for v4l2 regs, I think is implicit
> > > > > > that what regs that are not CCI are v4l2, then we return wit the
> > > > > > following defines:
> > > > > > 
> > > > > > 
> > > > > > 
> > > > > > #define REG_BCRM_REG_ADDR_R                           CCI_REG16(0x0014)
> > > > > > ^CCI regs
> > > > > > 
> > > > > > #define REG_BCRM_FEATURE_INQUIRY_R                    0x0008 
> > > > > > #define REG_BCRM_DEVICE_FIRMWARE_VERSION_R            0x0010
> > > > > > ^v4l2 regs
> > > > > 
> > > > > I'm not sure what you mean with "V4L2" registers ? I guess you mean
> > > > > registers which cannot be accessed through the CCI helper functions,
> > > > > but starting with v2 this is no longer true. There now is a CCI_REG64()
> > > > > so you can simply use that.
> > > > 
> > > > I'm playing a bit with v3 of your cci api :)
> > > > 
> > > > My problem is the following, bcrm regs are not real regs but are offset
> > > > from bcrm address (this is not fixed, it depends on the camera).
> > > > 
> > > > Then the workflow is:
> > > > 
> > > >  - read bcrm_address (base address)
> > > >  - then sum this to the offset (regs)
> > > > 
> > > > Myabe this clarify:
> > > > 
> > > > static int alvium_read(struct alvium_dev *alvium, u32 reg, u64 *val)
> > > 
> > > I would add a int *err argument to your read and write wrappers.
> > 
> > 
> > Thanks for your hint!
> > What about using:
> > 
> > static int alvium_write(struct alvium_dev *alvium, u32 reg, u64 val)
> > {
> > 	if (reg & REG_BCRM_V4L2) {
> > 		reg &= ~REG_BCRM_V4L2;
> > 		reg += alvium->bcrm_addr;
> > 	}
> > 
> > 	return cci_write(alvium->regmap, reg, val, NULL);
> > }
> > 
> > Then:
> > 
> > 	ret = alvium_write(alvium, reg, val);
> > 	if (ret) {
> > 		dev_err(dev, "Fail to write reg\n");
> > 		return ret;
> > 	}
> > 
> > 
> > I prefer to use this format if for you is ok.
> > Let me know.
> 
> This is fine when you have to write a single register only, but it makes
> things more complicated when writing multiple registers. Consider this:
> 
> 	int ret;
> 
> 	ret = alvium_write(alvium, REG_A, val);
> 	if (ret)
> 		return ret;
> 
> 	ret = alvium_write(alvium, REG_B, val);
> 	if (ret)
> 		return ret;
> 
> 	ret = alvium_write(alvium, REG_C, val);
> 	if (ret)
> 		return ret;
> 
> 	ret = alvium_write(alvium, REG_D, val);
> 	if (ret)
> 		return ret;
> 
> 	return 0;
> 
> and compare it to
> 
> 	int ret = 0;
> 
> 	alvium_write(alvium, REG_A, val, &ret);
> 	alvium_write(alvium, REG_B, val, &ret);
> 	alvium_write(alvium, REG_C, val, &ret);
> 	alvium_write(alvium, REG_D, val, &ret);
> 
> 	return ret;

Understood your reason.
Totally agree.
To be honest I did not think about it.

I'll fix this in v7. (I have also to fix .h tab space :'))

Thanks & Regards,
Tommaso

> 
> > > > {
> > > > 	int ret;
> > > > 
> > > > 	if (reg & REG_BCRM_V4L2)
> > > > 		reg += alvium->bcrm_addr;
> > > > 
> > > 
> > > You should also clear the REG_BCRM_V4L2 bit here:
> > > 
> > >  	if (reg & REG_BCRM_V4L2) {
> > > 		reg &= ~REG_BCRM_V4L2;
> > >  		reg += alvium->bcrm_addr;
> > > 	}
> > > 
> > > > 	cci_read(alvium->regmap, reg, val, &ret);
> > > > 	if (ret)
> > > > 		return ret;
> > > > 
> > > > 	return 0;
> > > 
> > > Just
> > > 
> > > 	return cci_read(alvium->regmap, reg, val, err);
> > > 
> > > Same for alvium_write()..
> > > 
> > > > }
> > > > 
> > > > int alvium_write(struct alvium_dev *alvium, u32 reg, u64 val)
> > > > {
> > > > 	int ret;
> > > > 
> > > > 	if (reg & REG_BCRM_V4L2)
> > > > 		reg += alvium->bcrm_addr;
> > > > 
> > > > 	cci_write(alvium->regmap, reg, val, &ret);
> > > > 	if (ret)
> > > > 		return ret;
> > > > 
> > > > 	return 0;
> > > > }
> > > > 
> > > > Where for example:
> > > > 
> > > > #define REG_BCRM_V4L2		BIT(31)
> > > > #define REG_BCRM_V4L2_64BIT(n)	(REG_BCRM_V4L2 | CCI_REG64(n))
> > > > 
> > > > #define REG_BCRM_WRITE_HANDSHAKE_RW REG_BCRM_V4L2_8BIT(0x0418)
> > > > 
> > > > 
> > > > But I'm not sure that I'm in the right direction. 
> > > 
> > > This looks good to me.
> > > 
> > > The fact that both Hans' helpers and part of the Alvium camera registers
> > > are named CCI is not a complete coincidence, but it doesn't mean they're
> > > identical. I would thus keep the REG_BCRM_CCI_* macros for clarity,
> > > simply defining them as CCI_* wrappers:
> > > 
> > > #define REG_BCRM_V4L2_8BIT(n)		CCI_REG8(n)
> > > ...
> > > 
> > > > In real I need first to get the real address then sum the bcrm_address
> > > > if this is a bcrm regs(offset) then re-incapsule the address into the
> > > > right CCI_REG# defines.
> > > > 
> > > > Then I'm not completely sure that cci fits my use case.
> > > > What do you think about?
> > > > 
> > > > Btw really great work! :)
> > > > 
> > > > > > ?
> > > > > > 
> > > > > >>> Note I'm about to send out a v3 addressing some small
> > > > > >>> remarks on this v2. I'll Cc you on that.
> > > > > >>
> > > > > >> Thanks, in this way I can test that and let you know my feedback.
> > > > > >>
> > > > > >>>> Let me know.
> > > > > >>>> Thanks! :)
> > > > > >>>>
> > > > > >>>> On Thu, Jun 15, 2023 at 12:21:00PM +0300, Laurent Pinchart wrote:
> > > > > >>>>> On Thu, Jun 15, 2023 at 11:11:20AM +0200, Hans de Goede wrote:
> > > > > >>>>>> On 6/14/23 23:48, Sakari Ailus wrote:
> > > > > >>>>>>> On Thu, Jun 15, 2023 at 12:34:29AM +0300, Laurent Pinchart wrote:
> > > > > >>>>>>>> On Wed, Jun 14, 2023 at 08:39:56PM +0000, Sakari Ailus wrote:
> > > > > >>>>>>>>> On Wed, Jun 14, 2023 at 09:23:39PM +0200, Hans de Goede wrote:
> > > > > >>>>>>>>>> The CSI2 specification specifies a standard method to access camera sensor
> > > > > >>>>>>>>>> registers called "Camera Control Interface (CCI)".
> > > > > >>>>>>>>>>
> > > > > >>>>>>>>>> This uses either 8 or 16 bit (big-endian wire order) register addresses
> > > > > >>>>>>>>>> and supports 8, 16, 24 or 32 bit (big-endian wire order) register widths.
> > > > > >>>>>>>>>>
> > > > > >>>>>>>>>> Currently a lot of Linux camera sensor drivers all have their own custom
> > > > > >>>>>>>>>> helpers for this, often copy and pasted from other drivers.
> > > > > >>>>>>>>>>
> > > > > >>>>>>>>>> Add a set of generic helpers for this so that all sensor drivers can
> > > > > >>>>>>>>>> switch to a single common implementation.
> > > > > >>>>>>>>>>
> > > > > >>>>>>>>>> These helpers take an extra optional "int *err" function parameter,
> > > > > >>>>>>>>>> this can be used to chain a bunch of register accesses together with
> > > > > >>>>>>>>>> only a single error check at the end, rather then needing to error
> > > > > >>>>>>>>>> check each individual register access. The first failing call will
> > > > > >>>>>>>>>> set the contents of err to a non 0 value and all other calls will
> > > > > >>>>>>>>>> then become no-ops.
> > > > > >>>>>>>>>>
> > > > > >>>>>>>>>> Link: https://lore.kernel.org/linux-media/59aefa7f-7bf9-6736-6040-39551329cd0a@redhat.com/
> > > > > >>>>>>>>>> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
> > > > > >>>>>>>>>> ---
> > > > > >>>>>>>>>> Changes in v2:
> > > > > >>>>>>>>>> - Drop cci_reg_type enum
> > > > > >>>>>>>>>> - Make having an encoded reg-width mandatory rather then using 0 to encode
> > > > > >>>>>>>>>>   8 bit width making reg-addresses without an encoded width default to
> > > > > >>>>>>>>>>   a width of 8
> > > > > >>>>>>>>>> - Add support for 64 bit wide registers
> > > > > >>>>>>>>
> > > > > >>>>>>>> I'm in two minds about this. This means that the read and write
> > > > > >>>>>>>> functions take a u64 argument, which will be less efficient on 32-bit
> > > > > >>>>>>>> platforms. I think it would be possible, with some macro magic, to
> > > > > >>>>>>>> accept different argument sizes, but maybe that's a micro-optimization
> > > > > >>>>>>>> that would actually result in worse code. 
> > > > > >>>>>>>>
> > > > > >>>>>>>> 64-bit support could be useful, but as far as I can tell, it's not used
> > > > > >>>>>>>> in this series, so maybe we could leave this for later ?
> > > > > >>>>>>>
> > > > > >>>>>>> I prefer to have it now, I just told Tommaso working on the Alvium driver
> > > > > >>>>>>> to use this, and he needs 64-bit access. :-)
> > > > > >>>>>>>
> > > > > >>>>>>> You could also easily have 32-bit and 64-bit variant of the functions, with
> > > > > >>>>>>> C11 _Generic(). Introducing it now would be easier than later.
> > > > > >>>>>>
> > > > > >>>>>> I took a quick look at C11 _Generic() and that looks at the type
> > > > > >>>>>> of "things" so in this case it would look at type of the val argument.
> > > > > >>>>>>
> > > > > >>>>>> Problem is that that can still be e.g. an int when doing a
> > > > > >>>>>> read/write from a 64 bit registers.
> > > > > >>>>>>
> > > > > >>>>>> So we would then need to handle the 64 bit width case in the 32
> > > > > >>>>>> bit versions of the functions too.
> > > > > >>>>>>
> > > > > >>>>>> And likewise I can see someone passing a long on a 64 bit
> > > > > >>>>>> arch while doing a cci_write() to a non 64 bit register.
> > > > > >>>>>>
> > > > > >>>>>> So this would basically mean copy and pasting cci_read()
> > > > > >>>>>> + cci_write() 2x with the only difference being one
> > > > > >>>>>> variant taking a 32 bit val argument and the other a
> > > > > >>>>>> 64 bit val argument.
> > > > > >>>>>>
> > > > > >>>>>> This seems like premature optimization to me.
> > > > > >>>>>>
> > > > > >>>>>> As mentioned in my reply to Laurent if we want to
> > > > > >>>>>> optimize things we really should look at avoiding
> > > > > >>>>>> unnecessary i2c transfers, or packing multiple
> > > > > >>>>>> writes into a single i2c transfer for writes to
> > > > > >>>>>> subsequent registers. That is where significant
> > > > > >>>>>> speedups can be made.
> > > > > >>>>>
> > > > > >>>>> This is something I'd really like to see, but it's way more work.
> > > > > >>>>>
> > > > > >>>>> There's an important need of applying changes atomically, which is often
> > > > > >>>>> not possible to strictly guarantee over I2C. Userspace ends up writing
> > > > > >>>>> V4L2 controls as quickly as it can after the start of a frame, hoping
> > > > > >>>>> they will all reach the sensor before the end of the frame. Some
> > > > > >>>>> platforms have camera-specific I2C controllers that have the ability to
> > > > > >>>>> buffer I2C transfers and issue them based on a hardware trigger. How to
> > > > > >>>>> fit this in thé kernel I2C API will be an interesting exercise.
> 
> -- 
> Regards,
> 
> Laurent Pinchart
Tommaso Merciai June 16, 2023, 2:15 p.m. UTC | #32
On Fri, Jun 16, 2023 at 04:41:24PM +0300, Laurent Pinchart wrote:
> Hi Tommaso,
> 
> On Fri, Jun 16, 2023 at 12:20:16AM +0200, Tommaso Merciai wrote:
> > On Thu, Jun 15, 2023 at 07:52:36PM +0300, Laurent Pinchart wrote:
> > > On Thu, Jun 15, 2023 at 06:15:43PM +0200, Tommaso Merciai wrote:
> > > > On Thu, Jun 15, 2023 at 02:00:46PM +0200, Hans de Goede wrote:
> > > > > On 6/15/23 13:54, Tommaso Merciai wrote:
> > > > > > On Thu, Jun 15, 2023 at 01:26:25PM +0200, Tommaso Merciai wrote:
> > > > > >> On Thu, Jun 15, 2023 at 01:10:40PM +0200, Hans de Goede wrote:
> > > > > >>> On 6/15/23 12:05, Tommaso Merciai wrote:
> > > > > >>>> Hi Hans, Laurent, Sakari,
> > > > > >>>>
> > > > > >>>> Can I cherry-pick this patch and use these new functions also
> > > > > >>>> for cci regs of the alvium driver?
> > > > > >>>
> > > > > >>> Yes that sounds like a good plan.
> > > > > >>>
> > > > > >>>> Are on going to be merge?
> > > > > >>>
> > > > > >>> Yes this will hopefully get merged upstream soon.
> > > > > >>
> > > > > >> Thanks for the info!
> > > > > >>
> > > > > >> I want to ask you your opinion about this:
> > > > > >>
> > > > > >> Into alvium driver actually I'm using the following defines
> > > > > >> manipulations:
> > > > > >>
> > > > > >> #define REG_BCRM_REG_ADDR_R				REG_BCRM_CCI_16BIT(0x0014)
> > > > > >>
> > > > > >> #define REG_BCRM_FEATURE_INQUIRY_R			REG_BCRM_V4L2_64BIT(0x0008)
> > > > > >> #define REG_BCRM_DEVICE_FIRMWARE_VERSION_R		REG_BCRM_V4L2_64BIT(0x0010)
> > > > > >>
> > > > > >> My plan is to use your cci API for cci register in this way defines
> > > > > >> became like:
> > > > > >>
> > > > > >> #define REG_BCRM_REG_ADDR_R				CCI_REG16(0x0014)
> > > > > >>
> > > > > >> And leave v4l2 regs are it are right now:
> > > > > >>
> > > > > >> #define REG_BCRM_FEATURE_INQUIRY_R			REG_BCRM_V4L2_64BIT(0x0008)
> > > > > >> #define REG_BCRM_DEVICE_FIRMWARE_VERSION_R		REG_BCRM_V4L2_64BIT(0x0010)
> > > > > >>
> > > > > >> What do you think about?
> > > > > > 
> > > > > > Or maybe is worth don't use v4l2 bit for v4l2 regs, I think is implicit
> > > > > > that what regs that are not CCI are v4l2, then we return wit the
> > > > > > following defines:
> > > > > > 
> > > > > > 
> > > > > > 
> > > > > > #define REG_BCRM_REG_ADDR_R                           CCI_REG16(0x0014)
> > > > > > ^CCI regs
> > > > > > 
> > > > > > #define REG_BCRM_FEATURE_INQUIRY_R                    0x0008 
> > > > > > #define REG_BCRM_DEVICE_FIRMWARE_VERSION_R            0x0010
> > > > > > ^v4l2 regs
> > > > > 
> > > > > I'm not sure what you mean with "V4L2" registers ? I guess you mean
> > > > > registers which cannot be accessed through the CCI helper functions,
> > > > > but starting with v2 this is no longer true. There now is a CCI_REG64()
> > > > > so you can simply use that.
> > > > 
> > > > I'm playing a bit with v3 of your cci api :)
> > > > 
> > > > My problem is the following, bcrm regs are not real regs but are offset
> > > > from bcrm address (this is not fixed, it depends on the camera).
> > > > 
> > > > Then the workflow is:
> > > > 
> > > >  - read bcrm_address (base address)
> > > >  - then sum this to the offset (regs)
> > > > 
> > > > Myabe this clarify:
> > > > 
> > > > static int alvium_read(struct alvium_dev *alvium, u32 reg, u64 *val)
> > > 
> > > I would add a int *err argument to your read and write wrappers.
> > 
> > 
> > Thanks for your hint!
> > What about using:
> > 
> > static int alvium_write(struct alvium_dev *alvium, u32 reg, u64 val)
> > {
> > 	if (reg & REG_BCRM_V4L2) {
> > 		reg &= ~REG_BCRM_V4L2;
> > 		reg += alvium->bcrm_addr;
> > 	}
> > 
> > 	return cci_write(alvium->regmap, reg, val, NULL);
> > }
> > 
> > Then:
> > 
> > 	ret = alvium_write(alvium, reg, val);
> > 	if (ret) {
> > 		dev_err(dev, "Fail to write reg\n");
> > 		return ret;
> > 	}
> > 
> > 
> > I prefer to use this format if for you is ok.
> > Let me know.
> 
> This is fine when you have to write a single register only, but it makes
> things more complicated when writing multiple registers. Consider this:
> 
> 	int ret;
> 
> 	ret = alvium_write(alvium, REG_A, val);
> 	if (ret)
> 		return ret;
> 
> 	ret = alvium_write(alvium, REG_B, val);
> 	if (ret)
> 		return ret;
> 
> 	ret = alvium_write(alvium, REG_C, val);
> 	if (ret)
> 		return ret;
> 
> 	ret = alvium_write(alvium, REG_D, val);
> 	if (ret)
> 		return ret;
> 
> 	return 0;
> 
> and compare it to
> 
> 	int ret = 0;
> 
> 	alvium_write(alvium, REG_A, val, &ret);
> 	alvium_write(alvium, REG_B, val, &ret);
> 	alvium_write(alvium, REG_C, val, &ret);
> 	alvium_write(alvium, REG_D, val, &ret);
> 
> 	return ret;

Is worth to add is also in alvium_write_hshake right?

Regards,
Tommaso

> 
> > > > {
> > > > 	int ret;
> > > > 
> > > > 	if (reg & REG_BCRM_V4L2)
> > > > 		reg += alvium->bcrm_addr;
> > > > 
> > > 
> > > You should also clear the REG_BCRM_V4L2 bit here:
> > > 
> > >  	if (reg & REG_BCRM_V4L2) {
> > > 		reg &= ~REG_BCRM_V4L2;
> > >  		reg += alvium->bcrm_addr;
> > > 	}
> > > 
> > > > 	cci_read(alvium->regmap, reg, val, &ret);
> > > > 	if (ret)
> > > > 		return ret;
> > > > 
> > > > 	return 0;
> > > 
> > > Just
> > > 
> > > 	return cci_read(alvium->regmap, reg, val, err);
> > > 
> > > Same for alvium_write()..
> > > 
> > > > }
> > > > 
> > > > int alvium_write(struct alvium_dev *alvium, u32 reg, u64 val)
> > > > {
> > > > 	int ret;
> > > > 
> > > > 	if (reg & REG_BCRM_V4L2)
> > > > 		reg += alvium->bcrm_addr;
> > > > 
> > > > 	cci_write(alvium->regmap, reg, val, &ret);
> > > > 	if (ret)
> > > > 		return ret;
> > > > 
> > > > 	return 0;
> > > > }
> > > > 
> > > > Where for example:
> > > > 
> > > > #define REG_BCRM_V4L2		BIT(31)
> > > > #define REG_BCRM_V4L2_64BIT(n)	(REG_BCRM_V4L2 | CCI_REG64(n))
> > > > 
> > > > #define REG_BCRM_WRITE_HANDSHAKE_RW REG_BCRM_V4L2_8BIT(0x0418)
> > > > 
> > > > 
> > > > But I'm not sure that I'm in the right direction. 
> > > 
> > > This looks good to me.
> > > 
> > > The fact that both Hans' helpers and part of the Alvium camera registers
> > > are named CCI is not a complete coincidence, but it doesn't mean they're
> > > identical. I would thus keep the REG_BCRM_CCI_* macros for clarity,
> > > simply defining them as CCI_* wrappers:
> > > 
> > > #define REG_BCRM_V4L2_8BIT(n)		CCI_REG8(n)
> > > ...
> > > 
> > > > In real I need first to get the real address then sum the bcrm_address
> > > > if this is a bcrm regs(offset) then re-incapsule the address into the
> > > > right CCI_REG# defines.
> > > > 
> > > > Then I'm not completely sure that cci fits my use case.
> > > > What do you think about?
> > > > 
> > > > Btw really great work! :)
> > > > 
> > > > > > ?
> > > > > > 
> > > > > >>> Note I'm about to send out a v3 addressing some small
> > > > > >>> remarks on this v2. I'll Cc you on that.
> > > > > >>
> > > > > >> Thanks, in this way I can test that and let you know my feedback.
> > > > > >>
> > > > > >>>> Let me know.
> > > > > >>>> Thanks! :)
> > > > > >>>>
> > > > > >>>> On Thu, Jun 15, 2023 at 12:21:00PM +0300, Laurent Pinchart wrote:
> > > > > >>>>> On Thu, Jun 15, 2023 at 11:11:20AM +0200, Hans de Goede wrote:
> > > > > >>>>>> On 6/14/23 23:48, Sakari Ailus wrote:
> > > > > >>>>>>> On Thu, Jun 15, 2023 at 12:34:29AM +0300, Laurent Pinchart wrote:
> > > > > >>>>>>>> On Wed, Jun 14, 2023 at 08:39:56PM +0000, Sakari Ailus wrote:
> > > > > >>>>>>>>> On Wed, Jun 14, 2023 at 09:23:39PM +0200, Hans de Goede wrote:
> > > > > >>>>>>>>>> The CSI2 specification specifies a standard method to access camera sensor
> > > > > >>>>>>>>>> registers called "Camera Control Interface (CCI)".
> > > > > >>>>>>>>>>
> > > > > >>>>>>>>>> This uses either 8 or 16 bit (big-endian wire order) register addresses
> > > > > >>>>>>>>>> and supports 8, 16, 24 or 32 bit (big-endian wire order) register widths.
> > > > > >>>>>>>>>>
> > > > > >>>>>>>>>> Currently a lot of Linux camera sensor drivers all have their own custom
> > > > > >>>>>>>>>> helpers for this, often copy and pasted from other drivers.
> > > > > >>>>>>>>>>
> > > > > >>>>>>>>>> Add a set of generic helpers for this so that all sensor drivers can
> > > > > >>>>>>>>>> switch to a single common implementation.
> > > > > >>>>>>>>>>
> > > > > >>>>>>>>>> These helpers take an extra optional "int *err" function parameter,
> > > > > >>>>>>>>>> this can be used to chain a bunch of register accesses together with
> > > > > >>>>>>>>>> only a single error check at the end, rather then needing to error
> > > > > >>>>>>>>>> check each individual register access. The first failing call will
> > > > > >>>>>>>>>> set the contents of err to a non 0 value and all other calls will
> > > > > >>>>>>>>>> then become no-ops.
> > > > > >>>>>>>>>>
> > > > > >>>>>>>>>> Link: https://lore.kernel.org/linux-media/59aefa7f-7bf9-6736-6040-39551329cd0a@redhat.com/
> > > > > >>>>>>>>>> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
> > > > > >>>>>>>>>> ---
> > > > > >>>>>>>>>> Changes in v2:
> > > > > >>>>>>>>>> - Drop cci_reg_type enum
> > > > > >>>>>>>>>> - Make having an encoded reg-width mandatory rather then using 0 to encode
> > > > > >>>>>>>>>>   8 bit width making reg-addresses without an encoded width default to
> > > > > >>>>>>>>>>   a width of 8
> > > > > >>>>>>>>>> - Add support for 64 bit wide registers
> > > > > >>>>>>>>
> > > > > >>>>>>>> I'm in two minds about this. This means that the read and write
> > > > > >>>>>>>> functions take a u64 argument, which will be less efficient on 32-bit
> > > > > >>>>>>>> platforms. I think it would be possible, with some macro magic, to
> > > > > >>>>>>>> accept different argument sizes, but maybe that's a micro-optimization
> > > > > >>>>>>>> that would actually result in worse code. 
> > > > > >>>>>>>>
> > > > > >>>>>>>> 64-bit support could be useful, but as far as I can tell, it's not used
> > > > > >>>>>>>> in this series, so maybe we could leave this for later ?
> > > > > >>>>>>>
> > > > > >>>>>>> I prefer to have it now, I just told Tommaso working on the Alvium driver
> > > > > >>>>>>> to use this, and he needs 64-bit access. :-)
> > > > > >>>>>>>
> > > > > >>>>>>> You could also easily have 32-bit and 64-bit variant of the functions, with
> > > > > >>>>>>> C11 _Generic(). Introducing it now would be easier than later.
> > > > > >>>>>>
> > > > > >>>>>> I took a quick look at C11 _Generic() and that looks at the type
> > > > > >>>>>> of "things" so in this case it would look at type of the val argument.
> > > > > >>>>>>
> > > > > >>>>>> Problem is that that can still be e.g. an int when doing a
> > > > > >>>>>> read/write from a 64 bit registers.
> > > > > >>>>>>
> > > > > >>>>>> So we would then need to handle the 64 bit width case in the 32
> > > > > >>>>>> bit versions of the functions too.
> > > > > >>>>>>
> > > > > >>>>>> And likewise I can see someone passing a long on a 64 bit
> > > > > >>>>>> arch while doing a cci_write() to a non 64 bit register.
> > > > > >>>>>>
> > > > > >>>>>> So this would basically mean copy and pasting cci_read()
> > > > > >>>>>> + cci_write() 2x with the only difference being one
> > > > > >>>>>> variant taking a 32 bit val argument and the other a
> > > > > >>>>>> 64 bit val argument.
> > > > > >>>>>>
> > > > > >>>>>> This seems like premature optimization to me.
> > > > > >>>>>>
> > > > > >>>>>> As mentioned in my reply to Laurent if we want to
> > > > > >>>>>> optimize things we really should look at avoiding
> > > > > >>>>>> unnecessary i2c transfers, or packing multiple
> > > > > >>>>>> writes into a single i2c transfer for writes to
> > > > > >>>>>> subsequent registers. That is where significant
> > > > > >>>>>> speedups can be made.
> > > > > >>>>>
> > > > > >>>>> This is something I'd really like to see, but it's way more work.
> > > > > >>>>>
> > > > > >>>>> There's an important need of applying changes atomically, which is often
> > > > > >>>>> not possible to strictly guarantee over I2C. Userspace ends up writing
> > > > > >>>>> V4L2 controls as quickly as it can after the start of a frame, hoping
> > > > > >>>>> they will all reach the sensor before the end of the frame. Some
> > > > > >>>>> platforms have camera-specific I2C controllers that have the ability to
> > > > > >>>>> buffer I2C transfers and issue them based on a hardware trigger. How to
> > > > > >>>>> fit this in thé kernel I2C API will be an interesting exercise.
> 
> -- 
> Regards,
> 
> Laurent Pinchart
Laurent Pinchart June 16, 2023, 2:17 p.m. UTC | #33
Hi Tommaso,

On Fri, Jun 16, 2023 at 04:15:09PM +0200, Tommaso Merciai wrote:
> On Fri, Jun 16, 2023 at 04:41:24PM +0300, Laurent Pinchart wrote:
> > On Fri, Jun 16, 2023 at 12:20:16AM +0200, Tommaso Merciai wrote:
> > > On Thu, Jun 15, 2023 at 07:52:36PM +0300, Laurent Pinchart wrote:
> > > > On Thu, Jun 15, 2023 at 06:15:43PM +0200, Tommaso Merciai wrote:
> > > > > On Thu, Jun 15, 2023 at 02:00:46PM +0200, Hans de Goede wrote:
> > > > > > On 6/15/23 13:54, Tommaso Merciai wrote:
> > > > > > > On Thu, Jun 15, 2023 at 01:26:25PM +0200, Tommaso Merciai wrote:
> > > > > > >> On Thu, Jun 15, 2023 at 01:10:40PM +0200, Hans de Goede wrote:
> > > > > > >>> On 6/15/23 12:05, Tommaso Merciai wrote:
> > > > > > >>>> Hi Hans, Laurent, Sakari,
> > > > > > >>>>
> > > > > > >>>> Can I cherry-pick this patch and use these new functions also
> > > > > > >>>> for cci regs of the alvium driver?
> > > > > > >>>
> > > > > > >>> Yes that sounds like a good plan.
> > > > > > >>>
> > > > > > >>>> Are on going to be merge?
> > > > > > >>>
> > > > > > >>> Yes this will hopefully get merged upstream soon.
> > > > > > >>
> > > > > > >> Thanks for the info!
> > > > > > >>
> > > > > > >> I want to ask you your opinion about this:
> > > > > > >>
> > > > > > >> Into alvium driver actually I'm using the following defines
> > > > > > >> manipulations:
> > > > > > >>
> > > > > > >> #define REG_BCRM_REG_ADDR_R				REG_BCRM_CCI_16BIT(0x0014)
> > > > > > >>
> > > > > > >> #define REG_BCRM_FEATURE_INQUIRY_R			REG_BCRM_V4L2_64BIT(0x0008)
> > > > > > >> #define REG_BCRM_DEVICE_FIRMWARE_VERSION_R		REG_BCRM_V4L2_64BIT(0x0010)
> > > > > > >>
> > > > > > >> My plan is to use your cci API for cci register in this way defines
> > > > > > >> became like:
> > > > > > >>
> > > > > > >> #define REG_BCRM_REG_ADDR_R				CCI_REG16(0x0014)
> > > > > > >>
> > > > > > >> And leave v4l2 regs are it are right now:
> > > > > > >>
> > > > > > >> #define REG_BCRM_FEATURE_INQUIRY_R			REG_BCRM_V4L2_64BIT(0x0008)
> > > > > > >> #define REG_BCRM_DEVICE_FIRMWARE_VERSION_R		REG_BCRM_V4L2_64BIT(0x0010)
> > > > > > >>
> > > > > > >> What do you think about?
> > > > > > > 
> > > > > > > Or maybe is worth don't use v4l2 bit for v4l2 regs, I think is implicit
> > > > > > > that what regs that are not CCI are v4l2, then we return wit the
> > > > > > > following defines:
> > > > > > > 
> > > > > > > 
> > > > > > > 
> > > > > > > #define REG_BCRM_REG_ADDR_R                           CCI_REG16(0x0014)
> > > > > > > ^CCI regs
> > > > > > > 
> > > > > > > #define REG_BCRM_FEATURE_INQUIRY_R                    0x0008 
> > > > > > > #define REG_BCRM_DEVICE_FIRMWARE_VERSION_R            0x0010
> > > > > > > ^v4l2 regs
> > > > > > 
> > > > > > I'm not sure what you mean with "V4L2" registers ? I guess you mean
> > > > > > registers which cannot be accessed through the CCI helper functions,
> > > > > > but starting with v2 this is no longer true. There now is a CCI_REG64()
> > > > > > so you can simply use that.
> > > > > 
> > > > > I'm playing a bit with v3 of your cci api :)
> > > > > 
> > > > > My problem is the following, bcrm regs are not real regs but are offset
> > > > > from bcrm address (this is not fixed, it depends on the camera).
> > > > > 
> > > > > Then the workflow is:
> > > > > 
> > > > >  - read bcrm_address (base address)
> > > > >  - then sum this to the offset (regs)
> > > > > 
> > > > > Myabe this clarify:
> > > > > 
> > > > > static int alvium_read(struct alvium_dev *alvium, u32 reg, u64 *val)
> > > > 
> > > > I would add a int *err argument to your read and write wrappers.
> > > 
> > > 
> > > Thanks for your hint!
> > > What about using:
> > > 
> > > static int alvium_write(struct alvium_dev *alvium, u32 reg, u64 val)
> > > {
> > > 	if (reg & REG_BCRM_V4L2) {
> > > 		reg &= ~REG_BCRM_V4L2;
> > > 		reg += alvium->bcrm_addr;
> > > 	}
> > > 
> > > 	return cci_write(alvium->regmap, reg, val, NULL);
> > > }
> > > 
> > > Then:
> > > 
> > > 	ret = alvium_write(alvium, reg, val);
> > > 	if (ret) {
> > > 		dev_err(dev, "Fail to write reg\n");
> > > 		return ret;
> > > 	}
> > > 
> > > 
> > > I prefer to use this format if for you is ok.
> > > Let me know.
> > 
> > This is fine when you have to write a single register only, but it makes
> > things more complicated when writing multiple registers. Consider this:
> > 
> > 	int ret;
> > 
> > 	ret = alvium_write(alvium, REG_A, val);
> > 	if (ret)
> > 		return ret;
> > 
> > 	ret = alvium_write(alvium, REG_B, val);
> > 	if (ret)
> > 		return ret;
> > 
> > 	ret = alvium_write(alvium, REG_C, val);
> > 	if (ret)
> > 		return ret;
> > 
> > 	ret = alvium_write(alvium, REG_D, val);
> > 	if (ret)
> > 		return ret;
> > 
> > 	return 0;
> > 
> > and compare it to
> > 
> > 	int ret = 0;
> > 
> > 	alvium_write(alvium, REG_A, val, &ret);
> > 	alvium_write(alvium, REG_B, val, &ret);
> > 	alvium_write(alvium, REG_C, val, &ret);
> > 	alvium_write(alvium, REG_D, val, &ret);
> > 
> > 	return ret;
> 
> Is worth to add is also in alvium_write_hshake right?

I'd say it's worth everywhere you can have multiple writes.

> > > > > {
> > > > > 	int ret;
> > > > > 
> > > > > 	if (reg & REG_BCRM_V4L2)
> > > > > 		reg += alvium->bcrm_addr;
> > > > > 
> > > > 
> > > > You should also clear the REG_BCRM_V4L2 bit here:
> > > > 
> > > >  	if (reg & REG_BCRM_V4L2) {
> > > > 		reg &= ~REG_BCRM_V4L2;
> > > >  		reg += alvium->bcrm_addr;
> > > > 	}
> > > > 
> > > > > 	cci_read(alvium->regmap, reg, val, &ret);
> > > > > 	if (ret)
> > > > > 		return ret;
> > > > > 
> > > > > 	return 0;
> > > > 
> > > > Just
> > > > 
> > > > 	return cci_read(alvium->regmap, reg, val, err);
> > > > 
> > > > Same for alvium_write()..
> > > > 
> > > > > }
> > > > > 
> > > > > int alvium_write(struct alvium_dev *alvium, u32 reg, u64 val)
> > > > > {
> > > > > 	int ret;
> > > > > 
> > > > > 	if (reg & REG_BCRM_V4L2)
> > > > > 		reg += alvium->bcrm_addr;
> > > > > 
> > > > > 	cci_write(alvium->regmap, reg, val, &ret);
> > > > > 	if (ret)
> > > > > 		return ret;
> > > > > 
> > > > > 	return 0;
> > > > > }
> > > > > 
> > > > > Where for example:
> > > > > 
> > > > > #define REG_BCRM_V4L2		BIT(31)
> > > > > #define REG_BCRM_V4L2_64BIT(n)	(REG_BCRM_V4L2 | CCI_REG64(n))
> > > > > 
> > > > > #define REG_BCRM_WRITE_HANDSHAKE_RW REG_BCRM_V4L2_8BIT(0x0418)
> > > > > 
> > > > > 
> > > > > But I'm not sure that I'm in the right direction. 
> > > > 
> > > > This looks good to me.
> > > > 
> > > > The fact that both Hans' helpers and part of the Alvium camera registers
> > > > are named CCI is not a complete coincidence, but it doesn't mean they're
> > > > identical. I would thus keep the REG_BCRM_CCI_* macros for clarity,
> > > > simply defining them as CCI_* wrappers:
> > > > 
> > > > #define REG_BCRM_V4L2_8BIT(n)		CCI_REG8(n)
> > > > ...
> > > > 
> > > > > In real I need first to get the real address then sum the bcrm_address
> > > > > if this is a bcrm regs(offset) then re-incapsule the address into the
> > > > > right CCI_REG# defines.
> > > > > 
> > > > > Then I'm not completely sure that cci fits my use case.
> > > > > What do you think about?
> > > > > 
> > > > > Btw really great work! :)
> > > > > 
> > > > > > > ?
> > > > > > > 
> > > > > > >>> Note I'm about to send out a v3 addressing some small
> > > > > > >>> remarks on this v2. I'll Cc you on that.
> > > > > > >>
> > > > > > >> Thanks, in this way I can test that and let you know my feedback.
> > > > > > >>
> > > > > > >>>> Let me know.
> > > > > > >>>> Thanks! :)
> > > > > > >>>>
> > > > > > >>>> On Thu, Jun 15, 2023 at 12:21:00PM +0300, Laurent Pinchart wrote:
> > > > > > >>>>> On Thu, Jun 15, 2023 at 11:11:20AM +0200, Hans de Goede wrote:
> > > > > > >>>>>> On 6/14/23 23:48, Sakari Ailus wrote:
> > > > > > >>>>>>> On Thu, Jun 15, 2023 at 12:34:29AM +0300, Laurent Pinchart wrote:
> > > > > > >>>>>>>> On Wed, Jun 14, 2023 at 08:39:56PM +0000, Sakari Ailus wrote:
> > > > > > >>>>>>>>> On Wed, Jun 14, 2023 at 09:23:39PM +0200, Hans de Goede wrote:
> > > > > > >>>>>>>>>> The CSI2 specification specifies a standard method to access camera sensor
> > > > > > >>>>>>>>>> registers called "Camera Control Interface (CCI)".
> > > > > > >>>>>>>>>>
> > > > > > >>>>>>>>>> This uses either 8 or 16 bit (big-endian wire order) register addresses
> > > > > > >>>>>>>>>> and supports 8, 16, 24 or 32 bit (big-endian wire order) register widths.
> > > > > > >>>>>>>>>>
> > > > > > >>>>>>>>>> Currently a lot of Linux camera sensor drivers all have their own custom
> > > > > > >>>>>>>>>> helpers for this, often copy and pasted from other drivers.
> > > > > > >>>>>>>>>>
> > > > > > >>>>>>>>>> Add a set of generic helpers for this so that all sensor drivers can
> > > > > > >>>>>>>>>> switch to a single common implementation.
> > > > > > >>>>>>>>>>
> > > > > > >>>>>>>>>> These helpers take an extra optional "int *err" function parameter,
> > > > > > >>>>>>>>>> this can be used to chain a bunch of register accesses together with
> > > > > > >>>>>>>>>> only a single error check at the end, rather then needing to error
> > > > > > >>>>>>>>>> check each individual register access. The first failing call will
> > > > > > >>>>>>>>>> set the contents of err to a non 0 value and all other calls will
> > > > > > >>>>>>>>>> then become no-ops.
> > > > > > >>>>>>>>>>
> > > > > > >>>>>>>>>> Link: https://lore.kernel.org/linux-media/59aefa7f-7bf9-6736-6040-39551329cd0a@redhat.com/
> > > > > > >>>>>>>>>> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
> > > > > > >>>>>>>>>> ---
> > > > > > >>>>>>>>>> Changes in v2:
> > > > > > >>>>>>>>>> - Drop cci_reg_type enum
> > > > > > >>>>>>>>>> - Make having an encoded reg-width mandatory rather then using 0 to encode
> > > > > > >>>>>>>>>>   8 bit width making reg-addresses without an encoded width default to
> > > > > > >>>>>>>>>>   a width of 8
> > > > > > >>>>>>>>>> - Add support for 64 bit wide registers
> > > > > > >>>>>>>>
> > > > > > >>>>>>>> I'm in two minds about this. This means that the read and write
> > > > > > >>>>>>>> functions take a u64 argument, which will be less efficient on 32-bit
> > > > > > >>>>>>>> platforms. I think it would be possible, with some macro magic, to
> > > > > > >>>>>>>> accept different argument sizes, but maybe that's a micro-optimization
> > > > > > >>>>>>>> that would actually result in worse code. 
> > > > > > >>>>>>>>
> > > > > > >>>>>>>> 64-bit support could be useful, but as far as I can tell, it's not used
> > > > > > >>>>>>>> in this series, so maybe we could leave this for later ?
> > > > > > >>>>>>>
> > > > > > >>>>>>> I prefer to have it now, I just told Tommaso working on the Alvium driver
> > > > > > >>>>>>> to use this, and he needs 64-bit access. :-)
> > > > > > >>>>>>>
> > > > > > >>>>>>> You could also easily have 32-bit and 64-bit variant of the functions, with
> > > > > > >>>>>>> C11 _Generic(). Introducing it now would be easier than later.
> > > > > > >>>>>>
> > > > > > >>>>>> I took a quick look at C11 _Generic() and that looks at the type
> > > > > > >>>>>> of "things" so in this case it would look at type of the val argument.
> > > > > > >>>>>>
> > > > > > >>>>>> Problem is that that can still be e.g. an int when doing a
> > > > > > >>>>>> read/write from a 64 bit registers.
> > > > > > >>>>>>
> > > > > > >>>>>> So we would then need to handle the 64 bit width case in the 32
> > > > > > >>>>>> bit versions of the functions too.
> > > > > > >>>>>>
> > > > > > >>>>>> And likewise I can see someone passing a long on a 64 bit
> > > > > > >>>>>> arch while doing a cci_write() to a non 64 bit register.
> > > > > > >>>>>>
> > > > > > >>>>>> So this would basically mean copy and pasting cci_read()
> > > > > > >>>>>> + cci_write() 2x with the only difference being one
> > > > > > >>>>>> variant taking a 32 bit val argument and the other a
> > > > > > >>>>>> 64 bit val argument.
> > > > > > >>>>>>
> > > > > > >>>>>> This seems like premature optimization to me.
> > > > > > >>>>>>
> > > > > > >>>>>> As mentioned in my reply to Laurent if we want to
> > > > > > >>>>>> optimize things we really should look at avoiding
> > > > > > >>>>>> unnecessary i2c transfers, or packing multiple
> > > > > > >>>>>> writes into a single i2c transfer for writes to
> > > > > > >>>>>> subsequent registers. That is where significant
> > > > > > >>>>>> speedups can be made.
> > > > > > >>>>>
> > > > > > >>>>> This is something I'd really like to see, but it's way more work.
> > > > > > >>>>>
> > > > > > >>>>> There's an important need of applying changes atomically, which is often
> > > > > > >>>>> not possible to strictly guarantee over I2C. Userspace ends up writing
> > > > > > >>>>> V4L2 controls as quickly as it can after the start of a frame, hoping
> > > > > > >>>>> they will all reach the sensor before the end of the frame. Some
> > > > > > >>>>> platforms have camera-specific I2C controllers that have the ability to
> > > > > > >>>>> buffer I2C transfers and issue them based on a hardware trigger. How to
> > > > > > >>>>> fit this in thé kernel I2C API will be an interesting exercise.
Tommaso Merciai June 16, 2023, 2:56 p.m. UTC | #34
Hi Laurent,

On Fri, Jun 16, 2023 at 05:17:06PM +0300, Laurent Pinchart wrote:
> Hi Tommaso,
> 
> On Fri, Jun 16, 2023 at 04:15:09PM +0200, Tommaso Merciai wrote:
> > On Fri, Jun 16, 2023 at 04:41:24PM +0300, Laurent Pinchart wrote:
> > > On Fri, Jun 16, 2023 at 12:20:16AM +0200, Tommaso Merciai wrote:
> > > > On Thu, Jun 15, 2023 at 07:52:36PM +0300, Laurent Pinchart wrote:
> > > > > On Thu, Jun 15, 2023 at 06:15:43PM +0200, Tommaso Merciai wrote:
> > > > > > On Thu, Jun 15, 2023 at 02:00:46PM +0200, Hans de Goede wrote:
> > > > > > > On 6/15/23 13:54, Tommaso Merciai wrote:
> > > > > > > > On Thu, Jun 15, 2023 at 01:26:25PM +0200, Tommaso Merciai wrote:
> > > > > > > >> On Thu, Jun 15, 2023 at 01:10:40PM +0200, Hans de Goede wrote:
> > > > > > > >>> On 6/15/23 12:05, Tommaso Merciai wrote:
> > > > > > > >>>> Hi Hans, Laurent, Sakari,
> > > > > > > >>>>
> > > > > > > >>>> Can I cherry-pick this patch and use these new functions also
> > > > > > > >>>> for cci regs of the alvium driver?
> > > > > > > >>>
> > > > > > > >>> Yes that sounds like a good plan.
> > > > > > > >>>
> > > > > > > >>>> Are on going to be merge?
> > > > > > > >>>
> > > > > > > >>> Yes this will hopefully get merged upstream soon.
> > > > > > > >>
> > > > > > > >> Thanks for the info!
> > > > > > > >>
> > > > > > > >> I want to ask you your opinion about this:
> > > > > > > >>
> > > > > > > >> Into alvium driver actually I'm using the following defines
> > > > > > > >> manipulations:
> > > > > > > >>
> > > > > > > >> #define REG_BCRM_REG_ADDR_R				REG_BCRM_CCI_16BIT(0x0014)
> > > > > > > >>
> > > > > > > >> #define REG_BCRM_FEATURE_INQUIRY_R			REG_BCRM_V4L2_64BIT(0x0008)
> > > > > > > >> #define REG_BCRM_DEVICE_FIRMWARE_VERSION_R		REG_BCRM_V4L2_64BIT(0x0010)
> > > > > > > >>
> > > > > > > >> My plan is to use your cci API for cci register in this way defines
> > > > > > > >> became like:
> > > > > > > >>
> > > > > > > >> #define REG_BCRM_REG_ADDR_R				CCI_REG16(0x0014)
> > > > > > > >>
> > > > > > > >> And leave v4l2 regs are it are right now:
> > > > > > > >>
> > > > > > > >> #define REG_BCRM_FEATURE_INQUIRY_R			REG_BCRM_V4L2_64BIT(0x0008)
> > > > > > > >> #define REG_BCRM_DEVICE_FIRMWARE_VERSION_R		REG_BCRM_V4L2_64BIT(0x0010)
> > > > > > > >>
> > > > > > > >> What do you think about?
> > > > > > > > 
> > > > > > > > Or maybe is worth don't use v4l2 bit for v4l2 regs, I think is implicit
> > > > > > > > that what regs that are not CCI are v4l2, then we return wit the
> > > > > > > > following defines:
> > > > > > > > 
> > > > > > > > 
> > > > > > > > 
> > > > > > > > #define REG_BCRM_REG_ADDR_R                           CCI_REG16(0x0014)
> > > > > > > > ^CCI regs
> > > > > > > > 
> > > > > > > > #define REG_BCRM_FEATURE_INQUIRY_R                    0x0008 
> > > > > > > > #define REG_BCRM_DEVICE_FIRMWARE_VERSION_R            0x0010
> > > > > > > > ^v4l2 regs
> > > > > > > 
> > > > > > > I'm not sure what you mean with "V4L2" registers ? I guess you mean
> > > > > > > registers which cannot be accessed through the CCI helper functions,
> > > > > > > but starting with v2 this is no longer true. There now is a CCI_REG64()
> > > > > > > so you can simply use that.
> > > > > > 
> > > > > > I'm playing a bit with v3 of your cci api :)
> > > > > > 
> > > > > > My problem is the following, bcrm regs are not real regs but are offset
> > > > > > from bcrm address (this is not fixed, it depends on the camera).
> > > > > > 
> > > > > > Then the workflow is:
> > > > > > 
> > > > > >  - read bcrm_address (base address)
> > > > > >  - then sum this to the offset (regs)
> > > > > > 
> > > > > > Myabe this clarify:
> > > > > > 
> > > > > > static int alvium_read(struct alvium_dev *alvium, u32 reg, u64 *val)
> > > > > 
> > > > > I would add a int *err argument to your read and write wrappers.
> > > > 
> > > > 
> > > > Thanks for your hint!
> > > > What about using:
> > > > 
> > > > static int alvium_write(struct alvium_dev *alvium, u32 reg, u64 val)
> > > > {
> > > > 	if (reg & REG_BCRM_V4L2) {
> > > > 		reg &= ~REG_BCRM_V4L2;
> > > > 		reg += alvium->bcrm_addr;
> > > > 	}
> > > > 
> > > > 	return cci_write(alvium->regmap, reg, val, NULL);
> > > > }
> > > > 
> > > > Then:
> > > > 
> > > > 	ret = alvium_write(alvium, reg, val);
> > > > 	if (ret) {
> > > > 		dev_err(dev, "Fail to write reg\n");
> > > > 		return ret;
> > > > 	}
> > > > 
> > > > 
> > > > I prefer to use this format if for you is ok.
> > > > Let me know.
> > > 
> > > This is fine when you have to write a single register only, but it makes
> > > things more complicated when writing multiple registers. Consider this:
> > > 
> > > 	int ret;
> > > 
> > > 	ret = alvium_write(alvium, REG_A, val);
> > > 	if (ret)
> > > 		return ret;
> > > 
> > > 	ret = alvium_write(alvium, REG_B, val);
> > > 	if (ret)
> > > 		return ret;
> > > 
> > > 	ret = alvium_write(alvium, REG_C, val);
> > > 	if (ret)
> > > 		return ret;
> > > 
> > > 	ret = alvium_write(alvium, REG_D, val);
> > > 	if (ret)
> > > 		return ret;
> > > 
> > > 	return 0;
> > > 
> > > and compare it to
> > > 
> > > 	int ret = 0;
> > > 
> > > 	alvium_write(alvium, REG_A, val, &ret);
> > > 	alvium_write(alvium, REG_B, val, &ret);
> > > 	alvium_write(alvium, REG_C, val, &ret);
> > > 	alvium_write(alvium, REG_D, val, &ret);
> > > 
> > > 	return ret;
> > 
> > Is worth to add is also in alvium_write_hshake right?

Checking this... :)

Most of the driver don't use so much sequence of writes/reads
and to be honest I want know where it fail


For example:

static int alvium_write_hshake(struct alvium_dev *alvium, u32 reg, u64 val,
							   int *err)
{
	struct device *dev = &alvium->i2c_client->dev;
	u64 hshake_regval;
	u8 hshake_bit;

	if (err && *err)
		return *err;

	if (!alvium->bcrm_addr)
		return -EINVAL;

	/* reset handshake bit */
	alvium_write(alvium, REG_BCRM_WRITE_HANDSHAKE_RW, 0, err);

	/* write alvium reg*/
	alvium_write(alvium, reg, val, err);

	/* poll handshake bit since bit0 = 1*/
	do {
		alvium_read(alvium, REG_BCRM_WRITE_HANDSHAKE_RW, &hshake_regval, err);
		hshake_bit = (hshake_regval & BCRM_HANDSHAKE_W_DONE_EN_BIT);

	} while (!hshake_bit);

	/* reset handshake bit, write 0 to bit0 */
	alvium_write(alvium, REG_BCRM_WRITE_HANDSHAKE_RW, 0, err);

	/* poll handshake bit since bit0 = 0 */
	do {
		alvium_read(alvium, REG_BCRM_WRITE_HANDSHAKE_RW, &hshake_regval, err);
		hshake_bit = (hshake_regval & BCRM_HANDSHAKE_W_DONE_EN_BIT);

	} while (hshake_bit);

	return *err;
}

If some write/read fail and have the same regs I want to know where the issue
is... Then I have to go back to the previous implementation..

I know that also cci API provides some print.
But maybe the older version is more straight forwed under debug
perspective...

Maybe is better to have more code in this case
This is my first impression following your way :)

Do you agree on this?

Regards,
Tommaso


> 
> I'd say it's worth everywhere you can have multiple writes.
> 
> > > > > > {
> > > > > > 	int ret;
> > > > > > 
> > > > > > 	if (reg & REG_BCRM_V4L2)
> > > > > > 		reg += alvium->bcrm_addr;
> > > > > > 
> > > > > 
> > > > > You should also clear the REG_BCRM_V4L2 bit here:
> > > > > 
> > > > >  	if (reg & REG_BCRM_V4L2) {
> > > > > 		reg &= ~REG_BCRM_V4L2;
> > > > >  		reg += alvium->bcrm_addr;
> > > > > 	}
> > > > > 
> > > > > > 	cci_read(alvium->regmap, reg, val, &ret);
> > > > > > 	if (ret)
> > > > > > 		return ret;
> > > > > > 
> > > > > > 	return 0;
> > > > > 
> > > > > Just
> > > > > 
> > > > > 	return cci_read(alvium->regmap, reg, val, err);
> > > > > 
> > > > > Same for alvium_write()..
> > > > > 
> > > > > > }
> > > > > > 
> > > > > > int alvium_write(struct alvium_dev *alvium, u32 reg, u64 val)
> > > > > > {
> > > > > > 	int ret;
> > > > > > 
> > > > > > 	if (reg & REG_BCRM_V4L2)
> > > > > > 		reg += alvium->bcrm_addr;
> > > > > > 
> > > > > > 	cci_write(alvium->regmap, reg, val, &ret);
> > > > > > 	if (ret)
> > > > > > 		return ret;
> > > > > > 
> > > > > > 	return 0;
> > > > > > }
> > > > > > 
> > > > > > Where for example:
> > > > > > 
> > > > > > #define REG_BCRM_V4L2		BIT(31)
> > > > > > #define REG_BCRM_V4L2_64BIT(n)	(REG_BCRM_V4L2 | CCI_REG64(n))
> > > > > > 
> > > > > > #define REG_BCRM_WRITE_HANDSHAKE_RW REG_BCRM_V4L2_8BIT(0x0418)
> > > > > > 
> > > > > > 
> > > > > > But I'm not sure that I'm in the right direction. 
> > > > > 
> > > > > This looks good to me.
> > > > > 
> > > > > The fact that both Hans' helpers and part of the Alvium camera registers
> > > > > are named CCI is not a complete coincidence, but it doesn't mean they're
> > > > > identical. I would thus keep the REG_BCRM_CCI_* macros for clarity,
> > > > > simply defining them as CCI_* wrappers:
> > > > > 
> > > > > #define REG_BCRM_V4L2_8BIT(n)		CCI_REG8(n)
> > > > > ...
> > > > > 
> > > > > > In real I need first to get the real address then sum the bcrm_address
> > > > > > if this is a bcrm regs(offset) then re-incapsule the address into the
> > > > > > right CCI_REG# defines.
> > > > > > 
> > > > > > Then I'm not completely sure that cci fits my use case.
> > > > > > What do you think about?
> > > > > > 
> > > > > > Btw really great work! :)
> > > > > > 
> > > > > > > > ?
> > > > > > > > 
> > > > > > > >>> Note I'm about to send out a v3 addressing some small
> > > > > > > >>> remarks on this v2. I'll Cc you on that.
> > > > > > > >>
> > > > > > > >> Thanks, in this way I can test that and let you know my feedback.
> > > > > > > >>
> > > > > > > >>>> Let me know.
> > > > > > > >>>> Thanks! :)
> > > > > > > >>>>
> > > > > > > >>>> On Thu, Jun 15, 2023 at 12:21:00PM +0300, Laurent Pinchart wrote:
> > > > > > > >>>>> On Thu, Jun 15, 2023 at 11:11:20AM +0200, Hans de Goede wrote:
> > > > > > > >>>>>> On 6/14/23 23:48, Sakari Ailus wrote:
> > > > > > > >>>>>>> On Thu, Jun 15, 2023 at 12:34:29AM +0300, Laurent Pinchart wrote:
> > > > > > > >>>>>>>> On Wed, Jun 14, 2023 at 08:39:56PM +0000, Sakari Ailus wrote:
> > > > > > > >>>>>>>>> On Wed, Jun 14, 2023 at 09:23:39PM +0200, Hans de Goede wrote:
> > > > > > > >>>>>>>>>> The CSI2 specification specifies a standard method to access camera sensor
> > > > > > > >>>>>>>>>> registers called "Camera Control Interface (CCI)".
> > > > > > > >>>>>>>>>>
> > > > > > > >>>>>>>>>> This uses either 8 or 16 bit (big-endian wire order) register addresses
> > > > > > > >>>>>>>>>> and supports 8, 16, 24 or 32 bit (big-endian wire order) register widths.
> > > > > > > >>>>>>>>>>
> > > > > > > >>>>>>>>>> Currently a lot of Linux camera sensor drivers all have their own custom
> > > > > > > >>>>>>>>>> helpers for this, often copy and pasted from other drivers.
> > > > > > > >>>>>>>>>>
> > > > > > > >>>>>>>>>> Add a set of generic helpers for this so that all sensor drivers can
> > > > > > > >>>>>>>>>> switch to a single common implementation.
> > > > > > > >>>>>>>>>>
> > > > > > > >>>>>>>>>> These helpers take an extra optional "int *err" function parameter,
> > > > > > > >>>>>>>>>> this can be used to chain a bunch of register accesses together with
> > > > > > > >>>>>>>>>> only a single error check at the end, rather then needing to error
> > > > > > > >>>>>>>>>> check each individual register access. The first failing call will
> > > > > > > >>>>>>>>>> set the contents of err to a non 0 value and all other calls will
> > > > > > > >>>>>>>>>> then become no-ops.
> > > > > > > >>>>>>>>>>
> > > > > > > >>>>>>>>>> Link: https://lore.kernel.org/linux-media/59aefa7f-7bf9-6736-6040-39551329cd0a@redhat.com/
> > > > > > > >>>>>>>>>> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
> > > > > > > >>>>>>>>>> ---
> > > > > > > >>>>>>>>>> Changes in v2:
> > > > > > > >>>>>>>>>> - Drop cci_reg_type enum
> > > > > > > >>>>>>>>>> - Make having an encoded reg-width mandatory rather then using 0 to encode
> > > > > > > >>>>>>>>>>   8 bit width making reg-addresses without an encoded width default to
> > > > > > > >>>>>>>>>>   a width of 8
> > > > > > > >>>>>>>>>> - Add support for 64 bit wide registers
> > > > > > > >>>>>>>>
> > > > > > > >>>>>>>> I'm in two minds about this. This means that the read and write
> > > > > > > >>>>>>>> functions take a u64 argument, which will be less efficient on 32-bit
> > > > > > > >>>>>>>> platforms. I think it would be possible, with some macro magic, to
> > > > > > > >>>>>>>> accept different argument sizes, but maybe that's a micro-optimization
> > > > > > > >>>>>>>> that would actually result in worse code. 
> > > > > > > >>>>>>>>
> > > > > > > >>>>>>>> 64-bit support could be useful, but as far as I can tell, it's not used
> > > > > > > >>>>>>>> in this series, so maybe we could leave this for later ?
> > > > > > > >>>>>>>
> > > > > > > >>>>>>> I prefer to have it now, I just told Tommaso working on the Alvium driver
> > > > > > > >>>>>>> to use this, and he needs 64-bit access. :-)
> > > > > > > >>>>>>>
> > > > > > > >>>>>>> You could also easily have 32-bit and 64-bit variant of the functions, with
> > > > > > > >>>>>>> C11 _Generic(). Introducing it now would be easier than later.
> > > > > > > >>>>>>
> > > > > > > >>>>>> I took a quick look at C11 _Generic() and that looks at the type
> > > > > > > >>>>>> of "things" so in this case it would look at type of the val argument.
> > > > > > > >>>>>>
> > > > > > > >>>>>> Problem is that that can still be e.g. an int when doing a
> > > > > > > >>>>>> read/write from a 64 bit registers.
> > > > > > > >>>>>>
> > > > > > > >>>>>> So we would then need to handle the 64 bit width case in the 32
> > > > > > > >>>>>> bit versions of the functions too.
> > > > > > > >>>>>>
> > > > > > > >>>>>> And likewise I can see someone passing a long on a 64 bit
> > > > > > > >>>>>> arch while doing a cci_write() to a non 64 bit register.
> > > > > > > >>>>>>
> > > > > > > >>>>>> So this would basically mean copy and pasting cci_read()
> > > > > > > >>>>>> + cci_write() 2x with the only difference being one
> > > > > > > >>>>>> variant taking a 32 bit val argument and the other a
> > > > > > > >>>>>> 64 bit val argument.
> > > > > > > >>>>>>
> > > > > > > >>>>>> This seems like premature optimization to me.
> > > > > > > >>>>>>
> > > > > > > >>>>>> As mentioned in my reply to Laurent if we want to
> > > > > > > >>>>>> optimize things we really should look at avoiding
> > > > > > > >>>>>> unnecessary i2c transfers, or packing multiple
> > > > > > > >>>>>> writes into a single i2c transfer for writes to
> > > > > > > >>>>>> subsequent registers. That is where significant
> > > > > > > >>>>>> speedups can be made.
> > > > > > > >>>>>
> > > > > > > >>>>> This is something I'd really like to see, but it's way more work.
> > > > > > > >>>>>
> > > > > > > >>>>> There's an important need of applying changes atomically, which is often
> > > > > > > >>>>> not possible to strictly guarantee over I2C. Userspace ends up writing
> > > > > > > >>>>> V4L2 controls as quickly as it can after the start of a frame, hoping
> > > > > > > >>>>> they will all reach the sensor before the end of the frame. Some
> > > > > > > >>>>> platforms have camera-specific I2C controllers that have the ability to
> > > > > > > >>>>> buffer I2C transfers and issue them based on a hardware trigger. How to
> > > > > > > >>>>> fit this in thé kernel I2C API will be an interesting exercise.
> 
> -- 
> Regards,
> 
> Laurent Pinchart
Laurent Pinchart June 16, 2023, 3:07 p.m. UTC | #35
On Fri, Jun 16, 2023 at 04:56:15PM +0200, Tommaso Merciai wrote:
> On Fri, Jun 16, 2023 at 05:17:06PM +0300, Laurent Pinchart wrote:
> > On Fri, Jun 16, 2023 at 04:15:09PM +0200, Tommaso Merciai wrote:
> > > On Fri, Jun 16, 2023 at 04:41:24PM +0300, Laurent Pinchart wrote:
> > > > On Fri, Jun 16, 2023 at 12:20:16AM +0200, Tommaso Merciai wrote:
> > > > > On Thu, Jun 15, 2023 at 07:52:36PM +0300, Laurent Pinchart wrote:
> > > > > > On Thu, Jun 15, 2023 at 06:15:43PM +0200, Tommaso Merciai wrote:
> > > > > > > On Thu, Jun 15, 2023 at 02:00:46PM +0200, Hans de Goede wrote:
> > > > > > > > On 6/15/23 13:54, Tommaso Merciai wrote:
> > > > > > > > > On Thu, Jun 15, 2023 at 01:26:25PM +0200, Tommaso Merciai wrote:
> > > > > > > > >> On Thu, Jun 15, 2023 at 01:10:40PM +0200, Hans de Goede wrote:
> > > > > > > > >>> On 6/15/23 12:05, Tommaso Merciai wrote:
> > > > > > > > >>>> Hi Hans, Laurent, Sakari,
> > > > > > > > >>>>
> > > > > > > > >>>> Can I cherry-pick this patch and use these new functions also
> > > > > > > > >>>> for cci regs of the alvium driver?
> > > > > > > > >>>
> > > > > > > > >>> Yes that sounds like a good plan.
> > > > > > > > >>>
> > > > > > > > >>>> Are on going to be merge?
> > > > > > > > >>>
> > > > > > > > >>> Yes this will hopefully get merged upstream soon.
> > > > > > > > >>
> > > > > > > > >> Thanks for the info!
> > > > > > > > >>
> > > > > > > > >> I want to ask you your opinion about this:
> > > > > > > > >>
> > > > > > > > >> Into alvium driver actually I'm using the following defines
> > > > > > > > >> manipulations:
> > > > > > > > >>
> > > > > > > > >> #define REG_BCRM_REG_ADDR_R				REG_BCRM_CCI_16BIT(0x0014)
> > > > > > > > >>
> > > > > > > > >> #define REG_BCRM_FEATURE_INQUIRY_R			REG_BCRM_V4L2_64BIT(0x0008)
> > > > > > > > >> #define REG_BCRM_DEVICE_FIRMWARE_VERSION_R		REG_BCRM_V4L2_64BIT(0x0010)
> > > > > > > > >>
> > > > > > > > >> My plan is to use your cci API for cci register in this way defines
> > > > > > > > >> became like:
> > > > > > > > >>
> > > > > > > > >> #define REG_BCRM_REG_ADDR_R				CCI_REG16(0x0014)
> > > > > > > > >>
> > > > > > > > >> And leave v4l2 regs are it are right now:
> > > > > > > > >>
> > > > > > > > >> #define REG_BCRM_FEATURE_INQUIRY_R			REG_BCRM_V4L2_64BIT(0x0008)
> > > > > > > > >> #define REG_BCRM_DEVICE_FIRMWARE_VERSION_R		REG_BCRM_V4L2_64BIT(0x0010)
> > > > > > > > >>
> > > > > > > > >> What do you think about?
> > > > > > > > > 
> > > > > > > > > Or maybe is worth don't use v4l2 bit for v4l2 regs, I think is implicit
> > > > > > > > > that what regs that are not CCI are v4l2, then we return wit the
> > > > > > > > > following defines:
> > > > > > > > > 
> > > > > > > > > 
> > > > > > > > > 
> > > > > > > > > #define REG_BCRM_REG_ADDR_R                           CCI_REG16(0x0014)
> > > > > > > > > ^CCI regs
> > > > > > > > > 
> > > > > > > > > #define REG_BCRM_FEATURE_INQUIRY_R                    0x0008 
> > > > > > > > > #define REG_BCRM_DEVICE_FIRMWARE_VERSION_R            0x0010
> > > > > > > > > ^v4l2 regs
> > > > > > > > 
> > > > > > > > I'm not sure what you mean with "V4L2" registers ? I guess you mean
> > > > > > > > registers which cannot be accessed through the CCI helper functions,
> > > > > > > > but starting with v2 this is no longer true. There now is a CCI_REG64()
> > > > > > > > so you can simply use that.
> > > > > > > 
> > > > > > > I'm playing a bit with v3 of your cci api :)
> > > > > > > 
> > > > > > > My problem is the following, bcrm regs are not real regs but are offset
> > > > > > > from bcrm address (this is not fixed, it depends on the camera).
> > > > > > > 
> > > > > > > Then the workflow is:
> > > > > > > 
> > > > > > >  - read bcrm_address (base address)
> > > > > > >  - then sum this to the offset (regs)
> > > > > > > 
> > > > > > > Myabe this clarify:
> > > > > > > 
> > > > > > > static int alvium_read(struct alvium_dev *alvium, u32 reg, u64 *val)
> > > > > > 
> > > > > > I would add a int *err argument to your read and write wrappers.
> > > > > 
> > > > > 
> > > > > Thanks for your hint!
> > > > > What about using:
> > > > > 
> > > > > static int alvium_write(struct alvium_dev *alvium, u32 reg, u64 val)
> > > > > {
> > > > > 	if (reg & REG_BCRM_V4L2) {
> > > > > 		reg &= ~REG_BCRM_V4L2;
> > > > > 		reg += alvium->bcrm_addr;
> > > > > 	}
> > > > > 
> > > > > 	return cci_write(alvium->regmap, reg, val, NULL);
> > > > > }
> > > > > 
> > > > > Then:
> > > > > 
> > > > > 	ret = alvium_write(alvium, reg, val);
> > > > > 	if (ret) {
> > > > > 		dev_err(dev, "Fail to write reg\n");
> > > > > 		return ret;
> > > > > 	}
> > > > > 
> > > > > 
> > > > > I prefer to use this format if for you is ok.
> > > > > Let me know.
> > > > 
> > > > This is fine when you have to write a single register only, but it makes
> > > > things more complicated when writing multiple registers. Consider this:
> > > > 
> > > > 	int ret;
> > > > 
> > > > 	ret = alvium_write(alvium, REG_A, val);
> > > > 	if (ret)
> > > > 		return ret;
> > > > 
> > > > 	ret = alvium_write(alvium, REG_B, val);
> > > > 	if (ret)
> > > > 		return ret;
> > > > 
> > > > 	ret = alvium_write(alvium, REG_C, val);
> > > > 	if (ret)
> > > > 		return ret;
> > > > 
> > > > 	ret = alvium_write(alvium, REG_D, val);
> > > > 	if (ret)
> > > > 		return ret;
> > > > 
> > > > 	return 0;
> > > > 
> > > > and compare it to
> > > > 
> > > > 	int ret = 0;
> > > > 
> > > > 	alvium_write(alvium, REG_A, val, &ret);
> > > > 	alvium_write(alvium, REG_B, val, &ret);
> > > > 	alvium_write(alvium, REG_C, val, &ret);
> > > > 	alvium_write(alvium, REG_D, val, &ret);
> > > > 
> > > > 	return ret;
> > > 
> > > Is worth to add is also in alvium_write_hshake right?
> 
> Checking this... :)
> 
> Most of the driver don't use so much sequence of writes/reads
> and to be honest I want know where it fail
> 
> 
> For example:
> 
> static int alvium_write_hshake(struct alvium_dev *alvium, u32 reg, u64 val,
> 							   int *err)
> {
> 	struct device *dev = &alvium->i2c_client->dev;
> 	u64 hshake_regval;
> 	u8 hshake_bit;
> 
> 	if (err && *err)
> 		return *err;
> 
> 	if (!alvium->bcrm_addr)
> 		return -EINVAL;
> 
> 	/* reset handshake bit */
> 	alvium_write(alvium, REG_BCRM_WRITE_HANDSHAKE_RW, 0, err);
> 
> 	/* write alvium reg*/
> 	alvium_write(alvium, reg, val, err);

You want to return here in case of error, as the poll loop below has no
chance of succeeding.

> 
> 	/* poll handshake bit since bit0 = 1*/
> 	do {
> 		alvium_read(alvium, REG_BCRM_WRITE_HANDSHAKE_RW, &hshake_regval, err);
> 		hshake_bit = (hshake_regval & BCRM_HANDSHAKE_W_DONE_EN_BIT);
> 
> 	} while (!hshake_bit);

This needs a timeout. The read_poll_timeout() macro can be useful. Same
below.

> 
> 	/* reset handshake bit, write 0 to bit0 */
> 	alvium_write(alvium, REG_BCRM_WRITE_HANDSHAKE_RW, 0, err);

This also needs to return if an error occurs.

> 
> 	/* poll handshake bit since bit0 = 0 */
> 	do {
> 		alvium_read(alvium, REG_BCRM_WRITE_HANDSHAKE_RW, &hshake_regval, err);
> 		hshake_bit = (hshake_regval & BCRM_HANDSHAKE_W_DONE_EN_BIT);
> 
> 	} while (hshake_bit);
> 
> 	return *err;
> }
> 
> If some write/read fail and have the same regs I want to know where the issue
> is... Then I have to go back to the previous implementation..
> 
> I know that also cci API provides some print.
> But maybe the older version is more straight forwed under debug
> perspective...
> 
> Maybe is better to have more code in this case
> This is my first impression following your way :)
> 
> Do you agree on this?

My comment was related to the callers of this function, not its internal
implementation. If there's a common pattern where alvium_write_hshake()
is called in a sequence of write operations then it should have an int
*err argument.

> > I'd say it's worth everywhere you can have multiple writes.
> > 
> > > > > > > {
> > > > > > > 	int ret;
> > > > > > > 
> > > > > > > 	if (reg & REG_BCRM_V4L2)
> > > > > > > 		reg += alvium->bcrm_addr;
> > > > > > > 
> > > > > > 
> > > > > > You should also clear the REG_BCRM_V4L2 bit here:
> > > > > > 
> > > > > >  	if (reg & REG_BCRM_V4L2) {
> > > > > > 		reg &= ~REG_BCRM_V4L2;
> > > > > >  		reg += alvium->bcrm_addr;
> > > > > > 	}
> > > > > > 
> > > > > > > 	cci_read(alvium->regmap, reg, val, &ret);
> > > > > > > 	if (ret)
> > > > > > > 		return ret;
> > > > > > > 
> > > > > > > 	return 0;
> > > > > > 
> > > > > > Just
> > > > > > 
> > > > > > 	return cci_read(alvium->regmap, reg, val, err);
> > > > > > 
> > > > > > Same for alvium_write()..
> > > > > > 
> > > > > > > }
> > > > > > > 
> > > > > > > int alvium_write(struct alvium_dev *alvium, u32 reg, u64 val)
> > > > > > > {
> > > > > > > 	int ret;
> > > > > > > 
> > > > > > > 	if (reg & REG_BCRM_V4L2)
> > > > > > > 		reg += alvium->bcrm_addr;
> > > > > > > 
> > > > > > > 	cci_write(alvium->regmap, reg, val, &ret);
> > > > > > > 	if (ret)
> > > > > > > 		return ret;
> > > > > > > 
> > > > > > > 	return 0;
> > > > > > > }
> > > > > > > 
> > > > > > > Where for example:
> > > > > > > 
> > > > > > > #define REG_BCRM_V4L2		BIT(31)
> > > > > > > #define REG_BCRM_V4L2_64BIT(n)	(REG_BCRM_V4L2 | CCI_REG64(n))
> > > > > > > 
> > > > > > > #define REG_BCRM_WRITE_HANDSHAKE_RW REG_BCRM_V4L2_8BIT(0x0418)
> > > > > > > 
> > > > > > > 
> > > > > > > But I'm not sure that I'm in the right direction. 
> > > > > > 
> > > > > > This looks good to me.
> > > > > > 
> > > > > > The fact that both Hans' helpers and part of the Alvium camera registers
> > > > > > are named CCI is not a complete coincidence, but it doesn't mean they're
> > > > > > identical. I would thus keep the REG_BCRM_CCI_* macros for clarity,
> > > > > > simply defining them as CCI_* wrappers:
> > > > > > 
> > > > > > #define REG_BCRM_V4L2_8BIT(n)		CCI_REG8(n)
> > > > > > ...
> > > > > > 
> > > > > > > In real I need first to get the real address then sum the bcrm_address
> > > > > > > if this is a bcrm regs(offset) then re-incapsule the address into the
> > > > > > > right CCI_REG# defines.
> > > > > > > 
> > > > > > > Then I'm not completely sure that cci fits my use case.
> > > > > > > What do you think about?
> > > > > > > 
> > > > > > > Btw really great work! :)
> > > > > > > 
> > > > > > > > > ?
> > > > > > > > > 
> > > > > > > > >>> Note I'm about to send out a v3 addressing some small
> > > > > > > > >>> remarks on this v2. I'll Cc you on that.
> > > > > > > > >>
> > > > > > > > >> Thanks, in this way I can test that and let you know my feedback.
> > > > > > > > >>
> > > > > > > > >>>> Let me know.
> > > > > > > > >>>> Thanks! :)
> > > > > > > > >>>>
> > > > > > > > >>>> On Thu, Jun 15, 2023 at 12:21:00PM +0300, Laurent Pinchart wrote:
> > > > > > > > >>>>> On Thu, Jun 15, 2023 at 11:11:20AM +0200, Hans de Goede wrote:
> > > > > > > > >>>>>> On 6/14/23 23:48, Sakari Ailus wrote:
> > > > > > > > >>>>>>> On Thu, Jun 15, 2023 at 12:34:29AM +0300, Laurent Pinchart wrote:
> > > > > > > > >>>>>>>> On Wed, Jun 14, 2023 at 08:39:56PM +0000, Sakari Ailus wrote:
> > > > > > > > >>>>>>>>> On Wed, Jun 14, 2023 at 09:23:39PM +0200, Hans de Goede wrote:
> > > > > > > > >>>>>>>>>> The CSI2 specification specifies a standard method to access camera sensor
> > > > > > > > >>>>>>>>>> registers called "Camera Control Interface (CCI)".
> > > > > > > > >>>>>>>>>>
> > > > > > > > >>>>>>>>>> This uses either 8 or 16 bit (big-endian wire order) register addresses
> > > > > > > > >>>>>>>>>> and supports 8, 16, 24 or 32 bit (big-endian wire order) register widths.
> > > > > > > > >>>>>>>>>>
> > > > > > > > >>>>>>>>>> Currently a lot of Linux camera sensor drivers all have their own custom
> > > > > > > > >>>>>>>>>> helpers for this, often copy and pasted from other drivers.
> > > > > > > > >>>>>>>>>>
> > > > > > > > >>>>>>>>>> Add a set of generic helpers for this so that all sensor drivers can
> > > > > > > > >>>>>>>>>> switch to a single common implementation.
> > > > > > > > >>>>>>>>>>
> > > > > > > > >>>>>>>>>> These helpers take an extra optional "int *err" function parameter,
> > > > > > > > >>>>>>>>>> this can be used to chain a bunch of register accesses together with
> > > > > > > > >>>>>>>>>> only a single error check at the end, rather then needing to error
> > > > > > > > >>>>>>>>>> check each individual register access. The first failing call will
> > > > > > > > >>>>>>>>>> set the contents of err to a non 0 value and all other calls will
> > > > > > > > >>>>>>>>>> then become no-ops.
> > > > > > > > >>>>>>>>>>
> > > > > > > > >>>>>>>>>> Link: https://lore.kernel.org/linux-media/59aefa7f-7bf9-6736-6040-39551329cd0a@redhat.com/
> > > > > > > > >>>>>>>>>> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
> > > > > > > > >>>>>>>>>> ---
> > > > > > > > >>>>>>>>>> Changes in v2:
> > > > > > > > >>>>>>>>>> - Drop cci_reg_type enum
> > > > > > > > >>>>>>>>>> - Make having an encoded reg-width mandatory rather then using 0 to encode
> > > > > > > > >>>>>>>>>>   8 bit width making reg-addresses without an encoded width default to
> > > > > > > > >>>>>>>>>>   a width of 8
> > > > > > > > >>>>>>>>>> - Add support for 64 bit wide registers
> > > > > > > > >>>>>>>>
> > > > > > > > >>>>>>>> I'm in two minds about this. This means that the read and write
> > > > > > > > >>>>>>>> functions take a u64 argument, which will be less efficient on 32-bit
> > > > > > > > >>>>>>>> platforms. I think it would be possible, with some macro magic, to
> > > > > > > > >>>>>>>> accept different argument sizes, but maybe that's a micro-optimization
> > > > > > > > >>>>>>>> that would actually result in worse code. 
> > > > > > > > >>>>>>>>
> > > > > > > > >>>>>>>> 64-bit support could be useful, but as far as I can tell, it's not used
> > > > > > > > >>>>>>>> in this series, so maybe we could leave this for later ?
> > > > > > > > >>>>>>>
> > > > > > > > >>>>>>> I prefer to have it now, I just told Tommaso working on the Alvium driver
> > > > > > > > >>>>>>> to use this, and he needs 64-bit access. :-)
> > > > > > > > >>>>>>>
> > > > > > > > >>>>>>> You could also easily have 32-bit and 64-bit variant of the functions, with
> > > > > > > > >>>>>>> C11 _Generic(). Introducing it now would be easier than later.
> > > > > > > > >>>>>>
> > > > > > > > >>>>>> I took a quick look at C11 _Generic() and that looks at the type
> > > > > > > > >>>>>> of "things" so in this case it would look at type of the val argument.
> > > > > > > > >>>>>>
> > > > > > > > >>>>>> Problem is that that can still be e.g. an int when doing a
> > > > > > > > >>>>>> read/write from a 64 bit registers.
> > > > > > > > >>>>>>
> > > > > > > > >>>>>> So we would then need to handle the 64 bit width case in the 32
> > > > > > > > >>>>>> bit versions of the functions too.
> > > > > > > > >>>>>>
> > > > > > > > >>>>>> And likewise I can see someone passing a long on a 64 bit
> > > > > > > > >>>>>> arch while doing a cci_write() to a non 64 bit register.
> > > > > > > > >>>>>>
> > > > > > > > >>>>>> So this would basically mean copy and pasting cci_read()
> > > > > > > > >>>>>> + cci_write() 2x with the only difference being one
> > > > > > > > >>>>>> variant taking a 32 bit val argument and the other a
> > > > > > > > >>>>>> 64 bit val argument.
> > > > > > > > >>>>>>
> > > > > > > > >>>>>> This seems like premature optimization to me.
> > > > > > > > >>>>>>
> > > > > > > > >>>>>> As mentioned in my reply to Laurent if we want to
> > > > > > > > >>>>>> optimize things we really should look at avoiding
> > > > > > > > >>>>>> unnecessary i2c transfers, or packing multiple
> > > > > > > > >>>>>> writes into a single i2c transfer for writes to
> > > > > > > > >>>>>> subsequent registers. That is where significant
> > > > > > > > >>>>>> speedups can be made.
> > > > > > > > >>>>>
> > > > > > > > >>>>> This is something I'd really like to see, but it's way more work.
> > > > > > > > >>>>>
> > > > > > > > >>>>> There's an important need of applying changes atomically, which is often
> > > > > > > > >>>>> not possible to strictly guarantee over I2C. Userspace ends up writing
> > > > > > > > >>>>> V4L2 controls as quickly as it can after the start of a frame, hoping
> > > > > > > > >>>>> they will all reach the sensor before the end of the frame. Some
> > > > > > > > >>>>> platforms have camera-specific I2C controllers that have the ability to
> > > > > > > > >>>>> buffer I2C transfers and issue them based on a hardware trigger. How to
> > > > > > > > >>>>> fit this in thé kernel I2C API will be an interesting exercise.
> > 
> > -- 
> > Regards,
> > 
> > Laurent Pinchart
Tommaso Merciai June 16, 2023, 4:34 p.m. UTC | #36
Hi Laurent,
Thanks for your comments.

On Fri, Jun 16, 2023 at 06:07:36PM +0300, Laurent Pinchart wrote:
> On Fri, Jun 16, 2023 at 04:56:15PM +0200, Tommaso Merciai wrote:
> > On Fri, Jun 16, 2023 at 05:17:06PM +0300, Laurent Pinchart wrote:
> > > On Fri, Jun 16, 2023 at 04:15:09PM +0200, Tommaso Merciai wrote:
> > > > On Fri, Jun 16, 2023 at 04:41:24PM +0300, Laurent Pinchart wrote:
> > > > > On Fri, Jun 16, 2023 at 12:20:16AM +0200, Tommaso Merciai wrote:
> > > > > > On Thu, Jun 15, 2023 at 07:52:36PM +0300, Laurent Pinchart wrote:
> > > > > > > On Thu, Jun 15, 2023 at 06:15:43PM +0200, Tommaso Merciai wrote:
> > > > > > > > On Thu, Jun 15, 2023 at 02:00:46PM +0200, Hans de Goede wrote:
> > > > > > > > > On 6/15/23 13:54, Tommaso Merciai wrote:
> > > > > > > > > > On Thu, Jun 15, 2023 at 01:26:25PM +0200, Tommaso Merciai wrote:
> > > > > > > > > >> On Thu, Jun 15, 2023 at 01:10:40PM +0200, Hans de Goede wrote:
> > > > > > > > > >>> On 6/15/23 12:05, Tommaso Merciai wrote:
> > > > > > > > > >>>> Hi Hans, Laurent, Sakari,
> > > > > > > > > >>>>
> > > > > > > > > >>>> Can I cherry-pick this patch and use these new functions also
> > > > > > > > > >>>> for cci regs of the alvium driver?
> > > > > > > > > >>>
> > > > > > > > > >>> Yes that sounds like a good plan.
> > > > > > > > > >>>
> > > > > > > > > >>>> Are on going to be merge?
> > > > > > > > > >>>
> > > > > > > > > >>> Yes this will hopefully get merged upstream soon.
> > > > > > > > > >>
> > > > > > > > > >> Thanks for the info!
> > > > > > > > > >>
> > > > > > > > > >> I want to ask you your opinion about this:
> > > > > > > > > >>
> > > > > > > > > >> Into alvium driver actually I'm using the following defines
> > > > > > > > > >> manipulations:
> > > > > > > > > >>
> > > > > > > > > >> #define REG_BCRM_REG_ADDR_R				REG_BCRM_CCI_16BIT(0x0014)
> > > > > > > > > >>
> > > > > > > > > >> #define REG_BCRM_FEATURE_INQUIRY_R			REG_BCRM_V4L2_64BIT(0x0008)
> > > > > > > > > >> #define REG_BCRM_DEVICE_FIRMWARE_VERSION_R		REG_BCRM_V4L2_64BIT(0x0010)
> > > > > > > > > >>
> > > > > > > > > >> My plan is to use your cci API for cci register in this way defines
> > > > > > > > > >> became like:
> > > > > > > > > >>
> > > > > > > > > >> #define REG_BCRM_REG_ADDR_R				CCI_REG16(0x0014)
> > > > > > > > > >>
> > > > > > > > > >> And leave v4l2 regs are it are right now:
> > > > > > > > > >>
> > > > > > > > > >> #define REG_BCRM_FEATURE_INQUIRY_R			REG_BCRM_V4L2_64BIT(0x0008)
> > > > > > > > > >> #define REG_BCRM_DEVICE_FIRMWARE_VERSION_R		REG_BCRM_V4L2_64BIT(0x0010)
> > > > > > > > > >>
> > > > > > > > > >> What do you think about?
> > > > > > > > > > 
> > > > > > > > > > Or maybe is worth don't use v4l2 bit for v4l2 regs, I think is implicit
> > > > > > > > > > that what regs that are not CCI are v4l2, then we return wit the
> > > > > > > > > > following defines:
> > > > > > > > > > 
> > > > > > > > > > 
> > > > > > > > > > 
> > > > > > > > > > #define REG_BCRM_REG_ADDR_R                           CCI_REG16(0x0014)
> > > > > > > > > > ^CCI regs
> > > > > > > > > > 
> > > > > > > > > > #define REG_BCRM_FEATURE_INQUIRY_R                    0x0008 
> > > > > > > > > > #define REG_BCRM_DEVICE_FIRMWARE_VERSION_R            0x0010
> > > > > > > > > > ^v4l2 regs
> > > > > > > > > 
> > > > > > > > > I'm not sure what you mean with "V4L2" registers ? I guess you mean
> > > > > > > > > registers which cannot be accessed through the CCI helper functions,
> > > > > > > > > but starting with v2 this is no longer true. There now is a CCI_REG64()
> > > > > > > > > so you can simply use that.
> > > > > > > > 
> > > > > > > > I'm playing a bit with v3 of your cci api :)
> > > > > > > > 
> > > > > > > > My problem is the following, bcrm regs are not real regs but are offset
> > > > > > > > from bcrm address (this is not fixed, it depends on the camera).
> > > > > > > > 
> > > > > > > > Then the workflow is:
> > > > > > > > 
> > > > > > > >  - read bcrm_address (base address)
> > > > > > > >  - then sum this to the offset (regs)
> > > > > > > > 
> > > > > > > > Myabe this clarify:
> > > > > > > > 
> > > > > > > > static int alvium_read(struct alvium_dev *alvium, u32 reg, u64 *val)
> > > > > > > 
> > > > > > > I would add a int *err argument to your read and write wrappers.
> > > > > > 
> > > > > > 
> > > > > > Thanks for your hint!
> > > > > > What about using:
> > > > > > 
> > > > > > static int alvium_write(struct alvium_dev *alvium, u32 reg, u64 val)
> > > > > > {
> > > > > > 	if (reg & REG_BCRM_V4L2) {
> > > > > > 		reg &= ~REG_BCRM_V4L2;
> > > > > > 		reg += alvium->bcrm_addr;
> > > > > > 	}
> > > > > > 
> > > > > > 	return cci_write(alvium->regmap, reg, val, NULL);
> > > > > > }
> > > > > > 
> > > > > > Then:
> > > > > > 
> > > > > > 	ret = alvium_write(alvium, reg, val);
> > > > > > 	if (ret) {
> > > > > > 		dev_err(dev, "Fail to write reg\n");
> > > > > > 		return ret;
> > > > > > 	}
> > > > > > 
> > > > > > 
> > > > > > I prefer to use this format if for you is ok.
> > > > > > Let me know.
> > > > > 
> > > > > This is fine when you have to write a single register only, but it makes
> > > > > things more complicated when writing multiple registers. Consider this:
> > > > > 
> > > > > 	int ret;
> > > > > 
> > > > > 	ret = alvium_write(alvium, REG_A, val);
> > > > > 	if (ret)
> > > > > 		return ret;
> > > > > 
> > > > > 	ret = alvium_write(alvium, REG_B, val);
> > > > > 	if (ret)
> > > > > 		return ret;
> > > > > 
> > > > > 	ret = alvium_write(alvium, REG_C, val);
> > > > > 	if (ret)
> > > > > 		return ret;
> > > > > 
> > > > > 	ret = alvium_write(alvium, REG_D, val);
> > > > > 	if (ret)
> > > > > 		return ret;
> > > > > 
> > > > > 	return 0;
> > > > > 
> > > > > and compare it to
> > > > > 
> > > > > 	int ret = 0;
> > > > > 
> > > > > 	alvium_write(alvium, REG_A, val, &ret);
> > > > > 	alvium_write(alvium, REG_B, val, &ret);
> > > > > 	alvium_write(alvium, REG_C, val, &ret);
> > > > > 	alvium_write(alvium, REG_D, val, &ret);
> > > > > 
> > > > > 	return ret;
> > > > 
> > > > Is worth to add is also in alvium_write_hshake right?
> > 
> > Checking this... :)
> > 
> > Most of the driver don't use so much sequence of writes/reads
> > and to be honest I want know where it fail
> > 
> > 
> > For example:
> > 
> > static int alvium_write_hshake(struct alvium_dev *alvium, u32 reg, u64 val,
> > 							   int *err)
> > {
> > 	struct device *dev = &alvium->i2c_client->dev;
> > 	u64 hshake_regval;
> > 	u8 hshake_bit;
> > 
> > 	if (err && *err)
> > 		return *err;
> > 
> > 	if (!alvium->bcrm_addr)
> > 		return -EINVAL;
> > 
> > 	/* reset handshake bit */
> > 	alvium_write(alvium, REG_BCRM_WRITE_HANDSHAKE_RW, 0, err);
> > 
> > 	/* write alvium reg*/
> > 	alvium_write(alvium, reg, val, err);
> 
> You want to return here in case of error, as the poll loop below has no
> chance of succeeding.
> 
> > 
> > 	/* poll handshake bit since bit0 = 1*/
> > 	do {
> > 		alvium_read(alvium, REG_BCRM_WRITE_HANDSHAKE_RW, &hshake_regval, err);
> > 		hshake_bit = (hshake_regval & BCRM_HANDSHAKE_W_DONE_EN_BIT);
> > 
> > 	} while (!hshake_bit);
> 
> This needs a timeout. The read_poll_timeout() macro can be useful. Same
> below.

Thanks! :)

> 
> > 
> > 	/* reset handshake bit, write 0 to bit0 */
> > 	alvium_write(alvium, REG_BCRM_WRITE_HANDSHAKE_RW, 0, err);
> 
> This also needs to return if an error occurs.
> 
> > 
> > 	/* poll handshake bit since bit0 = 0 */
> > 	do {
> > 		alvium_read(alvium, REG_BCRM_WRITE_HANDSHAKE_RW, &hshake_regval, err);
> > 		hshake_bit = (hshake_regval & BCRM_HANDSHAKE_W_DONE_EN_BIT);
> > 
> > 	} while (hshake_bit);
> > 
> > 	return *err;
> > }
> > 
> > If some write/read fail and have the same regs I want to know where the issue
> > is... Then I have to go back to the previous implementation..
> > 
> > I know that also cci API provides some print.
> > But maybe the older version is more straight forwed under debug
> > perspective...
> > 
> > Maybe is better to have more code in this case
> > This is my first impression following your way :)
> > 
> > Do you agree on this?
> 
> My comment was related to the callers of this function, not its internal
> implementation. If there's a common pattern where alvium_write_hshake()
> is called in a sequence of write operations then it should have an int
> *err argument.

My question is:

Except in the alvium_write_hshake function where you can see these
sequence of write/read operations? Same for _hshake_wrtie.
In my opinion there are not to much sequence of read/write operation
into the alvium driver, no?

I'm missing something?

Thanks & Regards,
Tommaso

> 
> > > I'd say it's worth everywhere you can have multiple writes.
> > > 
> > > > > > > > {
> > > > > > > > 	int ret;
> > > > > > > > 
> > > > > > > > 	if (reg & REG_BCRM_V4L2)
> > > > > > > > 		reg += alvium->bcrm_addr;
> > > > > > > > 
> > > > > > > 
> > > > > > > You should also clear the REG_BCRM_V4L2 bit here:
> > > > > > > 
> > > > > > >  	if (reg & REG_BCRM_V4L2) {
> > > > > > > 		reg &= ~REG_BCRM_V4L2;
> > > > > > >  		reg += alvium->bcrm_addr;
> > > > > > > 	}
> > > > > > > 
> > > > > > > > 	cci_read(alvium->regmap, reg, val, &ret);
> > > > > > > > 	if (ret)
> > > > > > > > 		return ret;
> > > > > > > > 
> > > > > > > > 	return 0;
> > > > > > > 
> > > > > > > Just
> > > > > > > 
> > > > > > > 	return cci_read(alvium->regmap, reg, val, err);
> > > > > > > 
> > > > > > > Same for alvium_write()..
> > > > > > > 
> > > > > > > > }
> > > > > > > > 
> > > > > > > > int alvium_write(struct alvium_dev *alvium, u32 reg, u64 val)
> > > > > > > > {
> > > > > > > > 	int ret;
> > > > > > > > 
> > > > > > > > 	if (reg & REG_BCRM_V4L2)
> > > > > > > > 		reg += alvium->bcrm_addr;
> > > > > > > > 
> > > > > > > > 	cci_write(alvium->regmap, reg, val, &ret);
> > > > > > > > 	if (ret)
> > > > > > > > 		return ret;
> > > > > > > > 
> > > > > > > > 	return 0;
> > > > > > > > }
> > > > > > > > 
> > > > > > > > Where for example:
> > > > > > > > 
> > > > > > > > #define REG_BCRM_V4L2		BIT(31)
> > > > > > > > #define REG_BCRM_V4L2_64BIT(n)	(REG_BCRM_V4L2 | CCI_REG64(n))
> > > > > > > > 
> > > > > > > > #define REG_BCRM_WRITE_HANDSHAKE_RW REG_BCRM_V4L2_8BIT(0x0418)
> > > > > > > > 
> > > > > > > > 
> > > > > > > > But I'm not sure that I'm in the right direction. 
> > > > > > > 
> > > > > > > This looks good to me.
> > > > > > > 
> > > > > > > The fact that both Hans' helpers and part of the Alvium camera registers
> > > > > > > are named CCI is not a complete coincidence, but it doesn't mean they're
> > > > > > > identical. I would thus keep the REG_BCRM_CCI_* macros for clarity,
> > > > > > > simply defining them as CCI_* wrappers:
> > > > > > > 
> > > > > > > #define REG_BCRM_V4L2_8BIT(n)		CCI_REG8(n)
> > > > > > > ...
> > > > > > > 
> > > > > > > > In real I need first to get the real address then sum the bcrm_address
> > > > > > > > if this is a bcrm regs(offset) then re-incapsule the address into the
> > > > > > > > right CCI_REG# defines.
> > > > > > > > 
> > > > > > > > Then I'm not completely sure that cci fits my use case.
> > > > > > > > What do you think about?
> > > > > > > > 
> > > > > > > > Btw really great work! :)
> > > > > > > > 
> > > > > > > > > > ?
> > > > > > > > > > 
> > > > > > > > > >>> Note I'm about to send out a v3 addressing some small
> > > > > > > > > >>> remarks on this v2. I'll Cc you on that.
> > > > > > > > > >>
> > > > > > > > > >> Thanks, in this way I can test that and let you know my feedback.
> > > > > > > > > >>
> > > > > > > > > >>>> Let me know.
> > > > > > > > > >>>> Thanks! :)
> > > > > > > > > >>>>
> > > > > > > > > >>>> On Thu, Jun 15, 2023 at 12:21:00PM +0300, Laurent Pinchart wrote:
> > > > > > > > > >>>>> On Thu, Jun 15, 2023 at 11:11:20AM +0200, Hans de Goede wrote:
> > > > > > > > > >>>>>> On 6/14/23 23:48, Sakari Ailus wrote:
> > > > > > > > > >>>>>>> On Thu, Jun 15, 2023 at 12:34:29AM +0300, Laurent Pinchart wrote:
> > > > > > > > > >>>>>>>> On Wed, Jun 14, 2023 at 08:39:56PM +0000, Sakari Ailus wrote:
> > > > > > > > > >>>>>>>>> On Wed, Jun 14, 2023 at 09:23:39PM +0200, Hans de Goede wrote:
> > > > > > > > > >>>>>>>>>> The CSI2 specification specifies a standard method to access camera sensor
> > > > > > > > > >>>>>>>>>> registers called "Camera Control Interface (CCI)".
> > > > > > > > > >>>>>>>>>>
> > > > > > > > > >>>>>>>>>> This uses either 8 or 16 bit (big-endian wire order) register addresses
> > > > > > > > > >>>>>>>>>> and supports 8, 16, 24 or 32 bit (big-endian wire order) register widths.
> > > > > > > > > >>>>>>>>>>
> > > > > > > > > >>>>>>>>>> Currently a lot of Linux camera sensor drivers all have their own custom
> > > > > > > > > >>>>>>>>>> helpers for this, often copy and pasted from other drivers.
> > > > > > > > > >>>>>>>>>>
> > > > > > > > > >>>>>>>>>> Add a set of generic helpers for this so that all sensor drivers can
> > > > > > > > > >>>>>>>>>> switch to a single common implementation.
> > > > > > > > > >>>>>>>>>>
> > > > > > > > > >>>>>>>>>> These helpers take an extra optional "int *err" function parameter,
> > > > > > > > > >>>>>>>>>> this can be used to chain a bunch of register accesses together with
> > > > > > > > > >>>>>>>>>> only a single error check at the end, rather then needing to error
> > > > > > > > > >>>>>>>>>> check each individual register access. The first failing call will
> > > > > > > > > >>>>>>>>>> set the contents of err to a non 0 value and all other calls will
> > > > > > > > > >>>>>>>>>> then become no-ops.
> > > > > > > > > >>>>>>>>>>
> > > > > > > > > >>>>>>>>>> Link: https://lore.kernel.org/linux-media/59aefa7f-7bf9-6736-6040-39551329cd0a@redhat.com/
> > > > > > > > > >>>>>>>>>> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
> > > > > > > > > >>>>>>>>>> ---
> > > > > > > > > >>>>>>>>>> Changes in v2:
> > > > > > > > > >>>>>>>>>> - Drop cci_reg_type enum
> > > > > > > > > >>>>>>>>>> - Make having an encoded reg-width mandatory rather then using 0 to encode
> > > > > > > > > >>>>>>>>>>   8 bit width making reg-addresses without an encoded width default to
> > > > > > > > > >>>>>>>>>>   a width of 8
> > > > > > > > > >>>>>>>>>> - Add support for 64 bit wide registers
> > > > > > > > > >>>>>>>>
> > > > > > > > > >>>>>>>> I'm in two minds about this. This means that the read and write
> > > > > > > > > >>>>>>>> functions take a u64 argument, which will be less efficient on 32-bit
> > > > > > > > > >>>>>>>> platforms. I think it would be possible, with some macro magic, to
> > > > > > > > > >>>>>>>> accept different argument sizes, but maybe that's a micro-optimization
> > > > > > > > > >>>>>>>> that would actually result in worse code. 
> > > > > > > > > >>>>>>>>
> > > > > > > > > >>>>>>>> 64-bit support could be useful, but as far as I can tell, it's not used
> > > > > > > > > >>>>>>>> in this series, so maybe we could leave this for later ?
> > > > > > > > > >>>>>>>
> > > > > > > > > >>>>>>> I prefer to have it now, I just told Tommaso working on the Alvium driver
> > > > > > > > > >>>>>>> to use this, and he needs 64-bit access. :-)
> > > > > > > > > >>>>>>>
> > > > > > > > > >>>>>>> You could also easily have 32-bit and 64-bit variant of the functions, with
> > > > > > > > > >>>>>>> C11 _Generic(). Introducing it now would be easier than later.
> > > > > > > > > >>>>>>
> > > > > > > > > >>>>>> I took a quick look at C11 _Generic() and that looks at the type
> > > > > > > > > >>>>>> of "things" so in this case it would look at type of the val argument.
> > > > > > > > > >>>>>>
> > > > > > > > > >>>>>> Problem is that that can still be e.g. an int when doing a
> > > > > > > > > >>>>>> read/write from a 64 bit registers.
> > > > > > > > > >>>>>>
> > > > > > > > > >>>>>> So we would then need to handle the 64 bit width case in the 32
> > > > > > > > > >>>>>> bit versions of the functions too.
> > > > > > > > > >>>>>>
> > > > > > > > > >>>>>> And likewise I can see someone passing a long on a 64 bit
> > > > > > > > > >>>>>> arch while doing a cci_write() to a non 64 bit register.
> > > > > > > > > >>>>>>
> > > > > > > > > >>>>>> So this would basically mean copy and pasting cci_read()
> > > > > > > > > >>>>>> + cci_write() 2x with the only difference being one
> > > > > > > > > >>>>>> variant taking a 32 bit val argument and the other a
> > > > > > > > > >>>>>> 64 bit val argument.
> > > > > > > > > >>>>>>
> > > > > > > > > >>>>>> This seems like premature optimization to me.
> > > > > > > > > >>>>>>
> > > > > > > > > >>>>>> As mentioned in my reply to Laurent if we want to
> > > > > > > > > >>>>>> optimize things we really should look at avoiding
> > > > > > > > > >>>>>> unnecessary i2c transfers, or packing multiple
> > > > > > > > > >>>>>> writes into a single i2c transfer for writes to
> > > > > > > > > >>>>>> subsequent registers. That is where significant
> > > > > > > > > >>>>>> speedups can be made.
> > > > > > > > > >>>>>
> > > > > > > > > >>>>> This is something I'd really like to see, but it's way more work.
> > > > > > > > > >>>>>
> > > > > > > > > >>>>> There's an important need of applying changes atomically, which is often
> > > > > > > > > >>>>> not possible to strictly guarantee over I2C. Userspace ends up writing
> > > > > > > > > >>>>> V4L2 controls as quickly as it can after the start of a frame, hoping
> > > > > > > > > >>>>> they will all reach the sensor before the end of the frame. Some
> > > > > > > > > >>>>> platforms have camera-specific I2C controllers that have the ability to
> > > > > > > > > >>>>> buffer I2C transfers and issue them based on a hardware trigger. How to
> > > > > > > > > >>>>> fit this in thé kernel I2C API will be an interesting exercise.
> > > 
> > > -- 
> > > Regards,
> > > 
> > > Laurent Pinchart
> 
> -- 
> Regards,
> 
> Laurent Pinchart
Hans de Goede June 16, 2023, 4:54 p.m. UTC | #37
Hi Tommaso,

On 6/15/23 18:15, Tommaso Merciai wrote:
> Hi Hans,
> 
> On Thu, Jun 15, 2023 at 02:00:46PM +0200, Hans de Goede wrote:
>> Hi,
>>
>> On 6/15/23 13:54, Tommaso Merciai wrote:
>>> On Thu, Jun 15, 2023 at 01:26:25PM +0200, Tommaso Merciai wrote:
>>>> Hi Hans,
>>>>
>>>> On Thu, Jun 15, 2023 at 01:10:40PM +0200, Hans de Goede wrote:
>>>>> Hi Tommaso,
>>>>>
>>>>> On 6/15/23 12:05, Tommaso Merciai wrote:
>>>>>> Hi Hans, Laurent, Sakari,
>>>>>>
>>>>>> Can I cherry-pick this patch and use these new functions also
>>>>>> for cci regs of the alvium driver?
>>>>>
>>>>> Yes that sounds like a good plan.
>>>>>
>>>>>> Are on going to be merge?
>>>>>
>>>>> Yes this will hopefully get merged upstream soon.
>>>>
>>>> Thanks for the info!
>>>>
>>>> I want to ask you your opinion about this:
>>>>
>>>> Into alvium driver actually I'm using the following defines
>>>> manipulations:
>>>>
>>>> #define REG_BCRM_REG_ADDR_R				REG_BCRM_CCI_16BIT(0x0014)
>>>>
>>>> #define REG_BCRM_FEATURE_INQUIRY_R			REG_BCRM_V4L2_64BIT(0x0008)
>>>> #define REG_BCRM_DEVICE_FIRMWARE_VERSION_R		REG_BCRM_V4L2_64BIT(0x0010)
>>>>
>>>> My plan is to use your cci API for cci register in this way defines
>>>> became like:
>>>>
>>>> #define REG_BCRM_REG_ADDR_R				CCI_REG16(0x0014)
>>>>
>>>> And leave v4l2 regs are it are right now:
>>>>
>>>> #define REG_BCRM_FEATURE_INQUIRY_R			REG_BCRM_V4L2_64BIT(0x0008)
>>>> #define REG_BCRM_DEVICE_FIRMWARE_VERSION_R		REG_BCRM_V4L2_64BIT(0x0010)
>>>>
>>>> What do you think about?
>>>
>>> Or maybe is worth don't use v4l2 bit for v4l2 regs, I think is implicit
>>> that what regs that are not CCI are v4l2, then we return wit the
>>> following defines:
>>>
>>>
>>>
>>> #define REG_BCRM_REG_ADDR_R                           CCI_REG16(0x0014)
>>> ^CCI regs
>>>
>>> #define REG_BCRM_FEATURE_INQUIRY_R                    0x0008 
>>> #define REG_BCRM_DEVICE_FIRMWARE_VERSION_R            0x0010
>>> ^v4l2 regs
>>
>> I'm not sure what you mean with "V4L2" registers ? I guess you mean
>> registers which cannot be accessed through the CCI helper functions,
>> but starting with v2 this is no longer true. There now is a CCI_REG64()
>> so you can simply use that.
> 
> I'm playing a bit with v3 of your cci api :)
> 
> My problem is the following, bcrm regs are not real regs but are offset
> from bcrm address (this is not fixed, it depends on the camera).
> 
> Then the workflow is:
> 
>  - read bcrm_address (base address)
>  - then sum this to the offset (regs)
> 
> Myabe this clarify:
> 
> static int alvium_read(struct alvium_dev *alvium, u32 reg, u64 *val)
> {
> 	int ret;
> 
> 	if (reg & REG_BCRM_V4L2)
> 		reg += alvium->bcrm_addr;
> 
> 	cci_read(alvium->regmap, reg, val, &ret);
> 	if (ret)
> 		return ret;
> 
> 	return 0;
> }
> 
> int alvium_write(struct alvium_dev *alvium, u32 reg, u64 val)
> {
> 	int ret;
> 
> 	if (reg & REG_BCRM_V4L2)
> 		reg += alvium->bcrm_addr;
> 
> 	cci_write(alvium->regmap, reg, val, &ret);
> 	if (ret)
> 		return ret;
> 
> 	return 0;
> }
> 
> Where for example:
> 
> #define REG_BCRM_V4L2		BIT(31)
> #define REG_BCRM_V4L2_64BIT(n)	(REG_BCRM_V4L2 | CCI_REG64(n))
> 
> #define REG_BCRM_WRITE_HANDSHAKE_RW REG_BCRM_V4L2_8BIT(0x0418)
> 
> 
> But I'm not sure that I'm in the right direction. 
> 
> In real I need first to get the real address then sum the bcrm_address
> if this is a bcrm regs(offset) then re-incapsule the address into the
> right CCI_REG# defines.

Ah I see, so you have a set of windowed registers where
the base address of these registers may change.

What I don't understand though is why you use V4L2 in the
name of the #defines for this? Does the datasheet actually
name them like this ? V4L2 stands for video4linux version 2,
so unless these registers are somehow Linux specific using
V4L2 in the #define names is a bit weird IMHO.

Regards,

Hans
Tommaso Merciai June 19, 2023, 8:13 a.m. UTC | #38
Hi Hans, Laurent,

On Fri, Jun 16, 2023 at 06:54:54PM +0200, Hans de Goede wrote:
> Hi Tommaso,
> 
> On 6/15/23 18:15, Tommaso Merciai wrote:
> > Hi Hans,
> > 
> > On Thu, Jun 15, 2023 at 02:00:46PM +0200, Hans de Goede wrote:
> >> Hi,
> >>
> >> On 6/15/23 13:54, Tommaso Merciai wrote:
> >>> On Thu, Jun 15, 2023 at 01:26:25PM +0200, Tommaso Merciai wrote:
> >>>> Hi Hans,
> >>>>
> >>>> On Thu, Jun 15, 2023 at 01:10:40PM +0200, Hans de Goede wrote:
> >>>>> Hi Tommaso,
> >>>>>
> >>>>> On 6/15/23 12:05, Tommaso Merciai wrote:
> >>>>>> Hi Hans, Laurent, Sakari,
> >>>>>>
> >>>>>> Can I cherry-pick this patch and use these new functions also
> >>>>>> for cci regs of the alvium driver?
> >>>>>
> >>>>> Yes that sounds like a good plan.
> >>>>>
> >>>>>> Are on going to be merge?
> >>>>>
> >>>>> Yes this will hopefully get merged upstream soon.
> >>>>
> >>>> Thanks for the info!
> >>>>
> >>>> I want to ask you your opinion about this:
> >>>>
> >>>> Into alvium driver actually I'm using the following defines
> >>>> manipulations:
> >>>>
> >>>> #define REG_BCRM_REG_ADDR_R				REG_BCRM_CCI_16BIT(0x0014)
> >>>>
> >>>> #define REG_BCRM_FEATURE_INQUIRY_R			REG_BCRM_V4L2_64BIT(0x0008)
> >>>> #define REG_BCRM_DEVICE_FIRMWARE_VERSION_R		REG_BCRM_V4L2_64BIT(0x0010)
> >>>>
> >>>> My plan is to use your cci API for cci register in this way defines
> >>>> became like:
> >>>>
> >>>> #define REG_BCRM_REG_ADDR_R				CCI_REG16(0x0014)
> >>>>
> >>>> And leave v4l2 regs are it are right now:
> >>>>
> >>>> #define REG_BCRM_FEATURE_INQUIRY_R			REG_BCRM_V4L2_64BIT(0x0008)
> >>>> #define REG_BCRM_DEVICE_FIRMWARE_VERSION_R		REG_BCRM_V4L2_64BIT(0x0010)
> >>>>
> >>>> What do you think about?
> >>>
> >>> Or maybe is worth don't use v4l2 bit for v4l2 regs, I think is implicit
> >>> that what regs that are not CCI are v4l2, then we return wit the
> >>> following defines:
> >>>
> >>>
> >>>
> >>> #define REG_BCRM_REG_ADDR_R                           CCI_REG16(0x0014)
> >>> ^CCI regs
> >>>
> >>> #define REG_BCRM_FEATURE_INQUIRY_R                    0x0008 
> >>> #define REG_BCRM_DEVICE_FIRMWARE_VERSION_R            0x0010
> >>> ^v4l2 regs
> >>
> >> I'm not sure what you mean with "V4L2" registers ? I guess you mean
> >> registers which cannot be accessed through the CCI helper functions,
> >> but starting with v2 this is no longer true. There now is a CCI_REG64()
> >> so you can simply use that.
> > 
> > I'm playing a bit with v3 of your cci api :)
> > 
> > My problem is the following, bcrm regs are not real regs but are offset
> > from bcrm address (this is not fixed, it depends on the camera).
> > 
> > Then the workflow is:
> > 
> >  - read bcrm_address (base address)
> >  - then sum this to the offset (regs)
> > 
> > Myabe this clarify:
> > 
> > static int alvium_read(struct alvium_dev *alvium, u32 reg, u64 *val)
> > {
> > 	int ret;
> > 
> > 	if (reg & REG_BCRM_V4L2)
> > 		reg += alvium->bcrm_addr;
> > 
> > 	cci_read(alvium->regmap, reg, val, &ret);
> > 	if (ret)
> > 		return ret;
> > 
> > 	return 0;
> > }
> > 
> > int alvium_write(struct alvium_dev *alvium, u32 reg, u64 val)
> > {
> > 	int ret;
> > 
> > 	if (reg & REG_BCRM_V4L2)
> > 		reg += alvium->bcrm_addr;
> > 
> > 	cci_write(alvium->regmap, reg, val, &ret);
> > 	if (ret)
> > 		return ret;
> > 
> > 	return 0;
> > }
> > 
> > Where for example:
> > 
> > #define REG_BCRM_V4L2		BIT(31)
> > #define REG_BCRM_V4L2_64BIT(n)	(REG_BCRM_V4L2 | CCI_REG64(n))
> > 
> > #define REG_BCRM_WRITE_HANDSHAKE_RW REG_BCRM_V4L2_8BIT(0x0418)
> > 
> > 
> > But I'm not sure that I'm in the right direction. 
> > 
> > In real I need first to get the real address then sum the bcrm_address
> > if this is a bcrm regs(offset) then re-incapsule the address into the
> > right CCI_REG# defines.
> 
> Ah I see, so you have a set of windowed registers where
> the base address of these registers may change.

Yep, right :)

> 
> What I don't understand though is why you use V4L2 in the
> name of the #defines for this? Does the datasheet actually
> name them like this ? V4L2 stands for video4linux version 2,
> so unless these registers are somehow Linux specific using
> V4L2 in the #define names is a bit weird IMHO.

These registers are offered from the alvium fw for v4l2 API.
We had a previous discussion with Laurent about this.

Btw I will send v7 with Laurent hints (read_timeout_poll/err-params)
And we can discuss there.

(If for you is ok :) )

I will keep both you and Laurent in CC.

Thanks again both for your review/hints :)

Regards,
Tommaso

> 
> Regards,
> 
> Hans
>
Hans de Goede June 19, 2023, 8:46 a.m. UTC | #39
Hi,

On 6/19/23 10:13, Tommaso Merciai wrote:
> Hi Hans, Laurent,
> 
> On Fri, Jun 16, 2023 at 06:54:54PM +0200, Hans de Goede wrote:
>> Hi Tommaso,
>>
>> On 6/15/23 18:15, Tommaso Merciai wrote:
>>> Hi Hans,
>>>
>>> On Thu, Jun 15, 2023 at 02:00:46PM +0200, Hans de Goede wrote:
>>>> Hi,
>>>>
>>>> On 6/15/23 13:54, Tommaso Merciai wrote:
>>>>> On Thu, Jun 15, 2023 at 01:26:25PM +0200, Tommaso Merciai wrote:
>>>>>> Hi Hans,
>>>>>>
>>>>>> On Thu, Jun 15, 2023 at 01:10:40PM +0200, Hans de Goede wrote:
>>>>>>> Hi Tommaso,
>>>>>>>
>>>>>>> On 6/15/23 12:05, Tommaso Merciai wrote:
>>>>>>>> Hi Hans, Laurent, Sakari,
>>>>>>>>
>>>>>>>> Can I cherry-pick this patch and use these new functions also
>>>>>>>> for cci regs of the alvium driver?
>>>>>>>
>>>>>>> Yes that sounds like a good plan.
>>>>>>>
>>>>>>>> Are on going to be merge?
>>>>>>>
>>>>>>> Yes this will hopefully get merged upstream soon.
>>>>>>
>>>>>> Thanks for the info!
>>>>>>
>>>>>> I want to ask you your opinion about this:
>>>>>>
>>>>>> Into alvium driver actually I'm using the following defines
>>>>>> manipulations:
>>>>>>
>>>>>> #define REG_BCRM_REG_ADDR_R				REG_BCRM_CCI_16BIT(0x0014)
>>>>>>
>>>>>> #define REG_BCRM_FEATURE_INQUIRY_R			REG_BCRM_V4L2_64BIT(0x0008)
>>>>>> #define REG_BCRM_DEVICE_FIRMWARE_VERSION_R		REG_BCRM_V4L2_64BIT(0x0010)
>>>>>>
>>>>>> My plan is to use your cci API for cci register in this way defines
>>>>>> became like:
>>>>>>
>>>>>> #define REG_BCRM_REG_ADDR_R				CCI_REG16(0x0014)
>>>>>>
>>>>>> And leave v4l2 regs are it are right now:
>>>>>>
>>>>>> #define REG_BCRM_FEATURE_INQUIRY_R			REG_BCRM_V4L2_64BIT(0x0008)
>>>>>> #define REG_BCRM_DEVICE_FIRMWARE_VERSION_R		REG_BCRM_V4L2_64BIT(0x0010)
>>>>>>
>>>>>> What do you think about?
>>>>>
>>>>> Or maybe is worth don't use v4l2 bit for v4l2 regs, I think is implicit
>>>>> that what regs that are not CCI are v4l2, then we return wit the
>>>>> following defines:
>>>>>
>>>>>
>>>>>
>>>>> #define REG_BCRM_REG_ADDR_R                           CCI_REG16(0x0014)
>>>>> ^CCI regs
>>>>>
>>>>> #define REG_BCRM_FEATURE_INQUIRY_R                    0x0008 
>>>>> #define REG_BCRM_DEVICE_FIRMWARE_VERSION_R            0x0010
>>>>> ^v4l2 regs
>>>>
>>>> I'm not sure what you mean with "V4L2" registers ? I guess you mean
>>>> registers which cannot be accessed through the CCI helper functions,
>>>> but starting with v2 this is no longer true. There now is a CCI_REG64()
>>>> so you can simply use that.
>>>
>>> I'm playing a bit with v3 of your cci api :)
>>>
>>> My problem is the following, bcrm regs are not real regs but are offset
>>> from bcrm address (this is not fixed, it depends on the camera).
>>>
>>> Then the workflow is:
>>>
>>>  - read bcrm_address (base address)
>>>  - then sum this to the offset (regs)
>>>
>>> Myabe this clarify:
>>>
>>> static int alvium_read(struct alvium_dev *alvium, u32 reg, u64 *val)
>>> {
>>> 	int ret;
>>>
>>> 	if (reg & REG_BCRM_V4L2)
>>> 		reg += alvium->bcrm_addr;
>>>
>>> 	cci_read(alvium->regmap, reg, val, &ret);
>>> 	if (ret)
>>> 		return ret;
>>>
>>> 	return 0;
>>> }
>>>
>>> int alvium_write(struct alvium_dev *alvium, u32 reg, u64 val)
>>> {
>>> 	int ret;
>>>
>>> 	if (reg & REG_BCRM_V4L2)
>>> 		reg += alvium->bcrm_addr;
>>>
>>> 	cci_write(alvium->regmap, reg, val, &ret);
>>> 	if (ret)
>>> 		return ret;
>>>
>>> 	return 0;
>>> }
>>>
>>> Where for example:
>>>
>>> #define REG_BCRM_V4L2		BIT(31)
>>> #define REG_BCRM_V4L2_64BIT(n)	(REG_BCRM_V4L2 | CCI_REG64(n))
>>>
>>> #define REG_BCRM_WRITE_HANDSHAKE_RW REG_BCRM_V4L2_8BIT(0x0418)
>>>
>>>
>>> But I'm not sure that I'm in the right direction. 
>>>
>>> In real I need first to get the real address then sum the bcrm_address
>>> if this is a bcrm regs(offset) then re-incapsule the address into the
>>> right CCI_REG# defines.
>>
>> Ah I see, so you have a set of windowed registers where
>> the base address of these registers may change.
> 
> Yep, right :)
> 
>>
>> What I don't understand though is why you use V4L2 in the
>> name of the #defines for this? Does the datasheet actually
>> name them like this ? V4L2 stands for video4linux version 2,
>> so unless these registers are somehow Linux specific using
>> V4L2 in the #define names is a bit weird IMHO.
> 
> These registers are offered from the alvium fw for v4l2 API.
> We had a previous discussion with Laurent about this.

Ah, ok that explains. Then the V4L2 in the register #defines makes
sense and I'm fine with it.

Regards,

Hans
diff mbox series

Patch

diff --git a/Documentation/driver-api/media/v4l2-cci.rst b/Documentation/driver-api/media/v4l2-cci.rst
new file mode 100644
index 000000000000..dd297a40ed20
--- /dev/null
+++ b/Documentation/driver-api/media/v4l2-cci.rst
@@ -0,0 +1,5 @@ 
+.. SPDX-License-Identifier: GPL-2.0
+
+V4L2 CCI kAPI
+^^^^^^^^^^^^^
+.. kernel-doc:: include/media/v4l2-cci.h
diff --git a/Documentation/driver-api/media/v4l2-core.rst b/Documentation/driver-api/media/v4l2-core.rst
index 1a8c4a5f256b..239045ecc8f4 100644
--- a/Documentation/driver-api/media/v4l2-core.rst
+++ b/Documentation/driver-api/media/v4l2-core.rst
@@ -22,6 +22,7 @@  Video4Linux devices
     v4l2-mem2mem
     v4l2-async
     v4l2-fwnode
+    v4l2-cci
     v4l2-rect
     v4l2-tuner
     v4l2-common
diff --git a/drivers/media/v4l2-core/Kconfig b/drivers/media/v4l2-core/Kconfig
index 348559bc2468..523ba243261d 100644
--- a/drivers/media/v4l2-core/Kconfig
+++ b/drivers/media/v4l2-core/Kconfig
@@ -74,6 +74,11 @@  config V4L2_FWNODE
 config V4L2_ASYNC
 	tristate
 
+config V4L2_CCI
+	tristate
+	depends on I2C
+	select REGMAP_I2C
+
 # Used by drivers that need Videobuf modules
 config VIDEOBUF_GEN
 	tristate
diff --git a/drivers/media/v4l2-core/Makefile b/drivers/media/v4l2-core/Makefile
index 41d91bd10cf2..be2551705755 100644
--- a/drivers/media/v4l2-core/Makefile
+++ b/drivers/media/v4l2-core/Makefile
@@ -25,6 +25,7 @@  videodev-$(CONFIG_VIDEO_V4L2_I2C) += v4l2-i2c.o
 # (e. g. LC_ALL=C sort Makefile)
 
 obj-$(CONFIG_V4L2_ASYNC) += v4l2-async.o
+obj-$(CONFIG_V4L2_CCI) += v4l2-cci.o
 obj-$(CONFIG_V4L2_FLASH_LED_CLASS) += v4l2-flash-led-class.o
 obj-$(CONFIG_V4L2_FWNODE) += v4l2-fwnode.o
 obj-$(CONFIG_V4L2_H264) += v4l2-h264.o
diff --git a/drivers/media/v4l2-core/v4l2-cci.c b/drivers/media/v4l2-core/v4l2-cci.c
new file mode 100644
index 000000000000..94764f3ebc6c
--- /dev/null
+++ b/drivers/media/v4l2-core/v4l2-cci.c
@@ -0,0 +1,157 @@ 
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * MIPI Camera Control Interface (CCI) register access helpers.
+ *
+ * Copyright (C) 2023 Hans de Goede <hansg@kernel.org>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/delay.h>
+#include <linux/dev_printk.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/types.h>
+
+#include <asm/unaligned.h>
+
+#include <media/v4l2-cci.h>
+
+int cci_read(struct regmap *map, u32 reg, u64 *val, int *err)
+{
+	int len, ret;
+	u8 buf[8];
+
+	if (err && *err)
+		return *err;
+
+	len = FIELD_GET(CCI_REG_WIDTH_MASK, reg);
+	reg = FIELD_GET(CCI_REG_ADDR_MASK, reg);
+
+	ret = regmap_bulk_read(map, reg, buf, len);
+	if (ret) {
+		dev_err(regmap_get_device(map), "Error reading reg 0x%4x: %d\n", reg, ret);
+		goto out;
+	}
+
+	switch (len) {
+	case 1:
+		*val = buf[0];
+		break;
+	case 2:
+		*val = get_unaligned_be16(buf);
+		break;
+	case 3:
+		*val = get_unaligned_be24(buf);
+		break;
+	case 4:
+		*val = get_unaligned_be32(buf);
+		break;
+	case 8:
+		*val = get_unaligned_be64(buf);
+		break;
+	default:
+		dev_err(regmap_get_device(map), "Error invalid reg-width %d for reg 0x%04x\n",
+			len, reg);
+		ret = -EINVAL;
+		break;
+	}
+
+out:
+	if (ret && err)
+		*err = ret;
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(cci_read);
+
+int cci_write(struct regmap *map, u32 reg, u64 val, int *err)
+{
+	int len, ret;
+	u8 buf[8];
+
+	if (err && *err)
+		return *err;
+
+	len = FIELD_GET(CCI_REG_WIDTH_MASK, reg);
+	reg = FIELD_GET(CCI_REG_ADDR_MASK, reg);
+
+	switch (len) {
+	case 1:
+		buf[0] = val;
+		break;
+	case 2:
+		put_unaligned_be16(val, buf);
+		break;
+	case 3:
+		put_unaligned_be24(val, buf);
+		break;
+	case 4:
+		put_unaligned_be32(val, buf);
+		break;
+	case 8:
+		put_unaligned_be64(val, buf);
+		break;
+	default:
+		dev_err(regmap_get_device(map), "Error invalid reg-width %d for reg 0x%04x\n",
+			len, reg);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	ret = regmap_bulk_write(map, reg, buf, len);
+	if (ret)
+		dev_err(regmap_get_device(map), "Error writing reg 0x%4x: %d\n", reg, ret);
+
+out:
+	if (ret && err)
+		*err = ret;
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(cci_write);
+
+int cci_update_bits(struct regmap *map, u32 reg, u64 mask, u64 val, int *err)
+{
+	u64 readval;
+	int ret;
+
+	ret = cci_read(map, reg, &readval, err);
+	if (ret)
+		return ret;
+
+	val = (readval & ~mask) | (val & mask);
+
+	return cci_write(map, reg, val, err);
+}
+EXPORT_SYMBOL_GPL(cci_update_bits);
+
+int cci_multi_reg_write(struct regmap *map, const struct cci_reg_sequence *regs,
+			int num_regs, int *err)
+{
+	int i, ret;
+
+	for (i = 0; i < num_regs; i++) {
+		ret = cci_write(map, regs[i].reg, regs[i].val, err);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(cci_multi_reg_write);
+
+struct regmap *cci_regmap_init_i2c(struct i2c_client *client, int reg_addr_bits)
+{
+	struct regmap_config config = {
+		.reg_bits = reg_addr_bits,
+		.val_bits = 8,
+		.reg_format_endian = REGMAP_ENDIAN_BIG,
+		.disable_locking = true,
+	};
+
+	return devm_regmap_init_i2c(client, &config);
+}
+EXPORT_SYMBOL_GPL(cci_regmap_init_i2c);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Hans de Goede <hansg@kernel.org>");
diff --git a/include/media/v4l2-cci.h b/include/media/v4l2-cci.h
new file mode 100644
index 000000000000..5d8fdff086db
--- /dev/null
+++ b/include/media/v4l2-cci.h
@@ -0,0 +1,121 @@ 
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * MIPI Camera Control Interface (CCI) register access helpers.
+ *
+ * Copyright (C) 2023 Hans de Goede <hansg@kernel.org>
+ */
+#ifndef _V4L2_CCI_H
+#define _V4L2_CCI_H
+
+#include <linux/types.h>
+
+struct i2c_client;
+struct reg_sequence;
+struct regmap;
+
+/**
+ * struct cci_reg_sequence - An individual write from a sequence of CCI writes
+ *
+ * @reg: Register address, use CCI_REG#() macros to encode reg width
+ * @val: Register value
+ *
+ * Register/value pairs for sequences of writes.
+ */
+struct cci_reg_sequence {
+	u32 reg;
+	u64 val;
+};
+
+/*
+ * Macros to define register address with the register width encoded
+ * into the higher bits.
+ */
+#define CCI_REG_ADDR_MASK		GENMASK(15, 0)
+#define CCI_REG_WIDTH_SHIFT		16
+#define CCI_REG_WIDTH_MASK		GENMASK(19, 16)
+
+#define CCI_REG8(x)			((1 << CCI_REG_WIDTH_SHIFT) | (x))
+#define CCI_REG16(x)			((2 << CCI_REG_WIDTH_SHIFT) | (x))
+#define CCI_REG24(x)			((3 << CCI_REG_WIDTH_SHIFT) | (x))
+#define CCI_REG32(x)			((4 << CCI_REG_WIDTH_SHIFT) | (x))
+#define CCI_REG64(x)			((8 << CCI_REG_WIDTH_SHIFT) | (x))
+
+/**
+ * cci_read() - Read a value from a single CCI register
+ *
+ * @map: Register map to read from
+ * @reg: Register address to read, use CCI_REG#() macros to encode reg width
+ * @val: Pointer to store read value
+ * @err: optional pointer to store errors, if a previous error is set
+ *       then the read will be skipped
+ *
+ * Return: %0 on success or a negative error code on failure.
+ */
+int cci_read(struct regmap *map, u32 reg, u64 *val, int *err);
+
+/**
+ * cci_write() - Write a value to a single CCI register
+ *
+ * @map: Register map to write to
+ * @reg: Register address to write, use CCI_REG#() macros to encode reg width
+ * @val: Value to be written
+ * @err: optional pointer to store errors, if a previous error is set
+ *       then the write will be skipped
+ *
+ * Return: %0 on success or a negative error code on failure.
+ */
+int cci_write(struct regmap *map, u32 reg, u64 val, int *err);
+
+/**
+ * cci_update_bits() - Perform a read/modify/write cycle on a single CCI register
+ *
+ * @map: Register map to update
+ * @reg: Register address to update, use CCI_REG#() macros to encode reg width
+ * @mask: Bitmask to change
+ * @val: New value for bitmask
+ * @err: optional pointer to store errors, if a previous error is set
+ *       then the update will be skipped
+ *
+ * Note this uses read-modify-write to update the bits, atomicity wrt other
+ * cci_*() register access functions is NOT guaranteed.
+ *
+ * Return: %0 on success or a negative error code on failure.
+ */
+int cci_update_bits(struct regmap *map, u32 reg, u64 mask, u64 val, int *err);
+
+/**
+ * cci_multi_reg_write() - Write multiple registers to the device
+ *
+ * @map: Register map to write to
+ * @regs: Array of structures containing register-address, value pairs to be written
+ *        register-addresses use CCI_REG#() macros to encode reg width
+ * @num_regs: Number of registers to write
+ * @err: optional pointer to store errors, if a previous error is set
+ *       then the write will be skipped
+ *
+ * Write multiple registers to the device where the set of register, value
+ * pairs are supplied in any order, possibly not all in a single range.
+ *
+ * Use of the CCI_REG#() macros to encode reg width is mandatory.
+ *
+ * For raw lists of register-address, -value pairs with only 8 bit
+ * wide writes regmap_multi_reg_write() can be used instead.
+ *
+ * Return: %0 on success or a negative error code on failure.
+ */
+int cci_multi_reg_write(struct regmap *map, const struct cci_reg_sequence *regs,
+			int num_regs, int *err);
+
+/**
+ * cci_regmap_init_i2c() - Create regmap to use with cci_*() register access functions
+ *
+ * @client: i2c_client to create the regmap for
+ * @reg_addr_bits: register address width to use (8 or 16)
+ *
+ * Note the memory for the created regmap is devm() managed, tied to the client.
+ *
+ * Return: %0 on success or a negative error code on failure.
+ */
+struct regmap *cci_regmap_init_i2c(struct i2c_client *client, int reg_addr_bits);
+
+#endif