bcm27xx: update 6.1 patches to latest version
[openwrt/staging/dangole.git] / target / linux / bcm27xx / patches-6.1 / 950-1192-media-Add-MIPI-CCI-register-access-helper-functions.patch
1 From ae0e1b70f675f6ac7966e427f0d8f57812dbc312 Mon Sep 17 00:00:00 2001
2 From: Hans de Goede <hdegoede@redhat.com>
3 Date: Tue, 27 Jun 2023 14:51:04 +0200
4 Subject: [PATCH] media: Add MIPI CCI register access helper functions
5
6 The CSI2 specification specifies a standard method to access camera sensor
7 registers called "Camera Control Interface (CCI)".
8
9 This uses either 8 or 16 bit (big-endian wire order) register addresses
10 and supports 8, 16, 24 or 32 bit (big-endian wire order) register widths.
11
12 Currently a lot of Linux camera sensor drivers all have their own custom
13 helpers for this, often copy and pasted from other drivers.
14
15 Add a set of generic helpers for this so that all sensor drivers can
16 switch to a single common implementation.
17
18 These helpers take an extra optional "int *err" function parameter,
19 this can be used to chain a bunch of register accesses together with
20 only a single error check at the end, rather than needing to error
21 check each individual register access. The first failing call will
22 set the contents of err to a non 0 value and all other calls will
23 then become no-ops.
24
25 Link: https://lore.kernel.org/linux-media/59aefa7f-7bf9-6736-6040-39551329cd0a@redhat.com/
26
27 Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
28 Tested-by: Tommaso Merciai <tomm.merciai@gmail.com>
29 Reviewed-by: Tommaso Merciai <tomm.merciai@gmail.com>
30 Signed-off-by: Hans de Goede <hdegoede@redhat.com>
31 Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
32 Signed-off-by: Mauro Carvalho Chehab <mchehab@kernel.org>
33 (cherry picked from commit 613cbb91e9cee7cf5a61f0816d2acab7bc117407)
34 ---
35 Documentation/driver-api/media/v4l2-cci.rst | 5 +
36 Documentation/driver-api/media/v4l2-core.rst | 1 +
37 drivers/media/v4l2-core/Kconfig | 9 +
38 drivers/media/v4l2-core/Makefile | 1 +
39 drivers/media/v4l2-core/v4l2-cci.c | 166 +++++++++++++++++++
40 include/media/v4l2-cci.h | 125 ++++++++++++++
41 6 files changed, 307 insertions(+)
42 create mode 100644 Documentation/driver-api/media/v4l2-cci.rst
43 create mode 100644 drivers/media/v4l2-core/v4l2-cci.c
44 create mode 100644 include/media/v4l2-cci.h
45
46 --- /dev/null
47 +++ b/Documentation/driver-api/media/v4l2-cci.rst
48 @@ -0,0 +1,5 @@
49 +.. SPDX-License-Identifier: GPL-2.0
50 +
51 +V4L2 CCI kAPI
52 +^^^^^^^^^^^^^
53 +.. kernel-doc:: include/media/v4l2-cci.h
54 --- a/Documentation/driver-api/media/v4l2-core.rst
55 +++ b/Documentation/driver-api/media/v4l2-core.rst
56 @@ -22,6 +22,7 @@ Video4Linux devices
57 v4l2-mem2mem
58 v4l2-async
59 v4l2-fwnode
60 + v4l2-cci
61 v4l2-rect
62 v4l2-tuner
63 v4l2-common
64 --- a/drivers/media/v4l2-core/Kconfig
65 +++ b/drivers/media/v4l2-core/Kconfig
66 @@ -74,6 +74,15 @@ config V4L2_FWNODE
67 config V4L2_ASYNC
68 tristate
69
70 +config V4L2_CCI
71 + tristate
72 +
73 +config V4L2_CCI_I2C
74 + tristate
75 + depends on I2C
76 + select REGMAP_I2C
77 + select V4L2_CCI
78 +
79 # Used by drivers that need Videobuf modules
80 config VIDEOBUF_GEN
81 tristate
82 --- a/drivers/media/v4l2-core/Makefile
83 +++ b/drivers/media/v4l2-core/Makefile
84 @@ -25,6 +25,7 @@ videodev-$(CONFIG_VIDEO_V4L2_I2C) += v4l
85 # (e. g. LC_ALL=C sort Makefile)
86
87 obj-$(CONFIG_V4L2_ASYNC) += v4l2-async.o
88 +obj-$(CONFIG_V4L2_CCI) += v4l2-cci.o
89 obj-$(CONFIG_V4L2_FLASH_LED_CLASS) += v4l2-flash-led-class.o
90 obj-$(CONFIG_V4L2_FWNODE) += v4l2-fwnode.o
91 obj-$(CONFIG_V4L2_H264) += v4l2-h264.o
92 --- /dev/null
93 +++ b/drivers/media/v4l2-core/v4l2-cci.c
94 @@ -0,0 +1,166 @@
95 +// SPDX-License-Identifier: GPL-2.0
96 +/*
97 + * MIPI Camera Control Interface (CCI) register access helpers.
98 + *
99 + * Copyright (C) 2023 Hans de Goede <hansg@kernel.org>
100 + */
101 +
102 +#include <linux/bitfield.h>
103 +#include <linux/delay.h>
104 +#include <linux/dev_printk.h>
105 +#include <linux/module.h>
106 +#include <linux/regmap.h>
107 +#include <linux/types.h>
108 +
109 +#include <asm/unaligned.h>
110 +
111 +#include <media/v4l2-cci.h>
112 +
113 +int cci_read(struct regmap *map, u32 reg, u64 *val, int *err)
114 +{
115 + unsigned int len;
116 + u8 buf[8];
117 + int ret;
118 +
119 + if (err && *err)
120 + return *err;
121 +
122 + len = FIELD_GET(CCI_REG_WIDTH_MASK, reg);
123 + reg = FIELD_GET(CCI_REG_ADDR_MASK, reg);
124 +
125 + ret = regmap_bulk_read(map, reg, buf, len);
126 + if (ret) {
127 + dev_err(regmap_get_device(map), "Error reading reg 0x%4x: %d\n",
128 + reg, ret);
129 + goto out;
130 + }
131 +
132 + switch (len) {
133 + case 1:
134 + *val = buf[0];
135 + break;
136 + case 2:
137 + *val = get_unaligned_be16(buf);
138 + break;
139 + case 3:
140 + *val = get_unaligned_be24(buf);
141 + break;
142 + case 4:
143 + *val = get_unaligned_be32(buf);
144 + break;
145 + case 8:
146 + *val = get_unaligned_be64(buf);
147 + break;
148 + default:
149 + dev_err(regmap_get_device(map), "Error invalid reg-width %u for reg 0x%04x\n",
150 + len, reg);
151 + ret = -EINVAL;
152 + break;
153 + }
154 +
155 +out:
156 + if (ret && err)
157 + *err = ret;
158 +
159 + return ret;
160 +}
161 +EXPORT_SYMBOL_GPL(cci_read);
162 +
163 +int cci_write(struct regmap *map, u32 reg, u64 val, int *err)
164 +{
165 + unsigned int len;
166 + u8 buf[8];
167 + int ret;
168 +
169 + if (err && *err)
170 + return *err;
171 +
172 + len = FIELD_GET(CCI_REG_WIDTH_MASK, reg);
173 + reg = FIELD_GET(CCI_REG_ADDR_MASK, reg);
174 +
175 + switch (len) {
176 + case 1:
177 + buf[0] = val;
178 + break;
179 + case 2:
180 + put_unaligned_be16(val, buf);
181 + break;
182 + case 3:
183 + put_unaligned_be24(val, buf);
184 + break;
185 + case 4:
186 + put_unaligned_be32(val, buf);
187 + break;
188 + case 8:
189 + put_unaligned_be64(val, buf);
190 + break;
191 + default:
192 + dev_err(regmap_get_device(map), "Error invalid reg-width %u for reg 0x%04x\n",
193 + len, reg);
194 + ret = -EINVAL;
195 + goto out;
196 + }
197 +
198 + ret = regmap_bulk_write(map, reg, buf, len);
199 + if (ret)
200 + dev_err(regmap_get_device(map), "Error writing reg 0x%4x: %d\n",
201 + reg, ret);
202 +
203 +out:
204 + if (ret && err)
205 + *err = ret;
206 +
207 + return ret;
208 +}
209 +EXPORT_SYMBOL_GPL(cci_write);
210 +
211 +int cci_update_bits(struct regmap *map, u32 reg, u64 mask, u64 val, int *err)
212 +{
213 + u64 readval;
214 + int ret;
215 +
216 + ret = cci_read(map, reg, &readval, err);
217 + if (ret)
218 + return ret;
219 +
220 + val = (readval & ~mask) | (val & mask);
221 +
222 + return cci_write(map, reg, val, err);
223 +}
224 +EXPORT_SYMBOL_GPL(cci_update_bits);
225 +
226 +int cci_multi_reg_write(struct regmap *map, const struct cci_reg_sequence *regs,
227 + unsigned int num_regs, int *err)
228 +{
229 + unsigned int i;
230 + int ret;
231 +
232 + for (i = 0; i < num_regs; i++) {
233 + ret = cci_write(map, regs[i].reg, regs[i].val, err);
234 + if (ret)
235 + return ret;
236 + }
237 +
238 + return 0;
239 +}
240 +EXPORT_SYMBOL_GPL(cci_multi_reg_write);
241 +
242 +#if IS_ENABLED(CONFIG_V4L2_CCI_I2C)
243 +struct regmap *devm_cci_regmap_init_i2c(struct i2c_client *client,
244 + int reg_addr_bits)
245 +{
246 + struct regmap_config config = {
247 + .reg_bits = reg_addr_bits,
248 + .val_bits = 8,
249 + .reg_format_endian = REGMAP_ENDIAN_BIG,
250 + .disable_locking = true,
251 + };
252 +
253 + return devm_regmap_init_i2c(client, &config);
254 +}
255 +EXPORT_SYMBOL_GPL(devm_cci_regmap_init_i2c);
256 +#endif
257 +
258 +MODULE_LICENSE("GPL");
259 +MODULE_AUTHOR("Hans de Goede <hansg@kernel.org>");
260 +MODULE_DESCRIPTION("MIPI Camera Control Interface (CCI) support");
261 --- /dev/null
262 +++ b/include/media/v4l2-cci.h
263 @@ -0,0 +1,125 @@
264 +/* SPDX-License-Identifier: GPL-2.0 */
265 +/*
266 + * MIPI Camera Control Interface (CCI) register access helpers.
267 + *
268 + * Copyright (C) 2023 Hans de Goede <hansg@kernel.org>
269 + */
270 +#ifndef _V4L2_CCI_H
271 +#define _V4L2_CCI_H
272 +
273 +#include <linux/types.h>
274 +
275 +struct i2c_client;
276 +struct regmap;
277 +
278 +/**
279 + * struct cci_reg_sequence - An individual write from a sequence of CCI writes
280 + *
281 + * @reg: Register address, use CCI_REG#() macros to encode reg width
282 + * @val: Register value
283 + *
284 + * Register/value pairs for sequences of writes.
285 + */
286 +struct cci_reg_sequence {
287 + u32 reg;
288 + u64 val;
289 +};
290 +
291 +/*
292 + * Macros to define register address with the register width encoded
293 + * into the higher bits.
294 + */
295 +#define CCI_REG_ADDR_MASK GENMASK(15, 0)
296 +#define CCI_REG_WIDTH_SHIFT 16
297 +#define CCI_REG_WIDTH_MASK GENMASK(19, 16)
298 +
299 +#define CCI_REG8(x) ((1 << CCI_REG_WIDTH_SHIFT) | (x))
300 +#define CCI_REG16(x) ((2 << CCI_REG_WIDTH_SHIFT) | (x))
301 +#define CCI_REG24(x) ((3 << CCI_REG_WIDTH_SHIFT) | (x))
302 +#define CCI_REG32(x) ((4 << CCI_REG_WIDTH_SHIFT) | (x))
303 +#define CCI_REG64(x) ((8 << CCI_REG_WIDTH_SHIFT) | (x))
304 +
305 +/**
306 + * cci_read() - Read a value from a single CCI register
307 + *
308 + * @map: Register map to read from
309 + * @reg: Register address to read, use CCI_REG#() macros to encode reg width
310 + * @val: Pointer to store read value
311 + * @err: Optional pointer to store errors, if a previous error is set
312 + * then the read will be skipped
313 + *
314 + * Return: %0 on success or a negative error code on failure.
315 + */
316 +int cci_read(struct regmap *map, u32 reg, u64 *val, int *err);
317 +
318 +/**
319 + * cci_write() - Write a value to a single CCI register
320 + *
321 + * @map: Register map to write to
322 + * @reg: Register address to write, use CCI_REG#() macros to encode reg width
323 + * @val: Value to be written
324 + * @err: Optional pointer to store errors, if a previous error is set
325 + * then the write will be skipped
326 + *
327 + * Return: %0 on success or a negative error code on failure.
328 + */
329 +int cci_write(struct regmap *map, u32 reg, u64 val, int *err);
330 +
331 +/**
332 + * cci_update_bits() - Perform a read/modify/write cycle on
333 + * a single CCI register
334 + *
335 + * @map: Register map to update
336 + * @reg: Register address to update, use CCI_REG#() macros to encode reg width
337 + * @mask: Bitmask to change
338 + * @val: New value for bitmask
339 + * @err: Optional pointer to store errors, if a previous error is set
340 + * then the update will be skipped
341 + *
342 + * Note this uses read-modify-write to update the bits, atomicity with regards
343 + * to other cci_*() register access functions is NOT guaranteed.
344 + *
345 + * Return: %0 on success or a negative error code on failure.
346 + */
347 +int cci_update_bits(struct regmap *map, u32 reg, u64 mask, u64 val, int *err);
348 +
349 +/**
350 + * cci_multi_reg_write() - Write multiple registers to the device
351 + *
352 + * @map: Register map to write to
353 + * @regs: Array of structures containing register-address, -value pairs to be
354 + * written, register-addresses use CCI_REG#() macros to encode reg width
355 + * @num_regs: Number of registers to write
356 + * @err: Optional pointer to store errors, if a previous error is set
357 + * then the write will be skipped
358 + *
359 + * Write multiple registers to the device where the set of register, value
360 + * pairs are supplied in any order, possibly not all in a single range.
361 + *
362 + * Use of the CCI_REG#() macros to encode reg width is mandatory.
363 + *
364 + * For raw lists of register-address, -value pairs with only 8 bit
365 + * wide writes regmap_multi_reg_write() can be used instead.
366 + *
367 + * Return: %0 on success or a negative error code on failure.
368 + */
369 +int cci_multi_reg_write(struct regmap *map, const struct cci_reg_sequence *regs,
370 + unsigned int num_regs, int *err);
371 +
372 +#if IS_ENABLED(CONFIG_V4L2_CCI_I2C)
373 +/**
374 + * devm_cci_regmap_init_i2c() - Create regmap to use with cci_*() register
375 + * access functions
376 + *
377 + * @client: i2c_client to create the regmap for
378 + * @reg_addr_bits: register address width to use (8 or 16)
379 + *
380 + * Note the memory for the created regmap is devm() managed, tied to the client.
381 + *
382 + * Return: %0 on success or a negative error code on failure.
383 + */
384 +struct regmap *devm_cci_regmap_init_i2c(struct i2c_client *client,
385 + int reg_addr_bits);
386 +#endif
387 +
388 +#endif