Linux Media Controller development
 help / color / mirror / Atom feed
From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
To: Sakari Ailus <sakari.ailus@linux.intel.com>
Cc: Hans de Goede <hdegoede@redhat.com>,
	Mauro Carvalho Chehab <mchehab@kernel.org>,
	Andy Shevchenko <andy@kernel.org>, Kate Hsuan <hpa@redhat.com>,
	linux-media@vger.kernel.org
Subject: Re: [PATCH v2 1/5] media: Add MIPI CCI register access helper functions
Date: Thu, 15 Jun 2023 00:34:29 +0300	[thread overview]
Message-ID: <20230614213429.GA28757@pendragon.ideasonboard.com> (raw)
In-Reply-To: <ZIolnOxs29H8EUmC@kekkonen.localdomain>

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?

-- 
Regards,

Laurent Pinchart

  reply	other threads:[~2023-06-14 21:34 UTC|newest]

Thread overview: 53+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-06-14 19:23 [PATCH v2 0/5] media: Add MIPI CCI register access helper functions Hans de Goede
2023-06-14 19:23 ` [PATCH v2 1/5] " Hans de Goede
2023-06-14 20:09   ` Andy Shevchenko
2023-06-14 20:39   ` Sakari Ailus
2023-06-14 21:34     ` Laurent Pinchart [this message]
2023-06-14 21:48       ` Sakari Ailus
2023-06-14 22:11         ` Laurent Pinchart
2023-06-15  9:11         ` Hans de Goede
2023-06-15  9:21           ` Laurent Pinchart
2023-06-15 10:05             ` Tommaso Merciai
2023-06-15 11:10               ` Hans de Goede
2023-06-15 11:26                 ` Tommaso Merciai
2023-06-15 11:54                   ` Tommaso Merciai
2023-06-15 12:00                     ` Hans de Goede
2023-06-15 16:15                       ` Tommaso Merciai
2023-06-15 16:52                         ` Laurent Pinchart
2023-06-15 22:20                           ` Tommaso Merciai
2023-06-16 13:41                             ` Laurent Pinchart
2023-06-16 14:08                               ` Tommaso Merciai
2023-06-16 14:15                               ` Tommaso Merciai
2023-06-16 14:17                                 ` Laurent Pinchart
2023-06-16 14:56                                   ` Tommaso Merciai
2023-06-16 15:07                                     ` Laurent Pinchart
2023-06-16 16:34                                       ` Tommaso Merciai
2023-06-16 16:54                         ` Hans de Goede
2023-06-19  8:13                           ` Tommaso Merciai
2023-06-19  8:46                             ` Hans de Goede
2023-06-15 10:08           ` Sakari Ailus
2023-06-15  8:56       ` Hans de Goede
2023-06-14 22:21     ` Andy Shevchenko
2023-06-14 22:24       ` Andy Shevchenko
2023-06-15  8:45     ` Hans de Goede
2023-06-15  9:54       ` Sakari Ailus
2023-06-15 10:15         ` Hans de Goede
2023-06-15 10:35           ` Andy Shevchenko
2023-06-15 11:41           ` Sakari Ailus
2023-06-15 12:05             ` Hans de Goede
2023-06-15 13:19               ` Sakari Ailus
2023-06-15 13:28                 ` Sakari Ailus
2023-06-15 13:52                 ` Hans de Goede
2023-06-15 13:23             ` Andy Shevchenko
2023-06-14 19:23 ` [PATCH v2 2/5] media: ov5693: Convert to new CCI register access helpers Hans de Goede
2023-06-14 20:13   ` Andy Shevchenko
2023-06-15  9:16     ` Hans de Goede
2023-06-14 21:54   ` Laurent Pinchart
2023-06-14 19:23 ` [PATCH v2 3/5] media: imx290: " Hans de Goede
2023-06-14 22:04   ` Laurent Pinchart
2023-06-14 19:23 ` [PATCH v2 4/5] media: atomisp: ov2680: " Hans de Goede
2023-06-14 20:15   ` Andy Shevchenko
2023-06-15  9:02     ` Hans de Goede
2023-06-15 10:16       ` Andy Shevchenko
2023-06-14 19:23 ` [PATCH v2 5/5] media: Remove ov_16bit_addr_reg_helpers.h Hans de Goede
2023-06-14 20:17   ` Andy Shevchenko

Reply instructions:

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

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

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

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

  git send-email \
    --in-reply-to=20230614213429.GA28757@pendragon.ideasonboard.com \
    --to=laurent.pinchart@ideasonboard.com \
    --cc=andy@kernel.org \
    --cc=hdegoede@redhat.com \
    --cc=hpa@redhat.com \
    --cc=linux-media@vger.kernel.org \
    --cc=mchehab@kernel.org \
    --cc=sakari.ailus@linux.intel.com \
    /path/to/YOUR_REPLY

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

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox