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
next prev parent 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