Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

media: Add MIPI CCI register access helper functions

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 than 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/

Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
Tested-by: Tommaso Merciai <tomm.merciai@gmail.com>
Reviewed-by: Tommaso Merciai <tomm.merciai@gmail.com>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@kernel.org>

authored by

Hans de Goede and committed by
Mauro Carvalho Chehab
613cbb91 35a29918

+307
+5
Documentation/driver-api/media/v4l2-cci.rst
··· 1 + .. SPDX-License-Identifier: GPL-2.0 2 + 3 + V4L2 CCI kAPI 4 + ^^^^^^^^^^^^^ 5 + .. kernel-doc:: include/media/v4l2-cci.h
+1
Documentation/driver-api/media/v4l2-core.rst
··· 22 22 v4l2-mem2mem 23 23 v4l2-async 24 24 v4l2-fwnode 25 + v4l2-cci 25 26 v4l2-rect 26 27 v4l2-tuner 27 28 v4l2-common
+9
drivers/media/v4l2-core/Kconfig
··· 74 74 config V4L2_ASYNC 75 75 tristate 76 76 77 + config V4L2_CCI 78 + tristate 79 + 80 + config V4L2_CCI_I2C 81 + tristate 82 + depends on I2C 83 + select REGMAP_I2C 84 + select V4L2_CCI 85 + 77 86 # Used by drivers that need Videobuf modules 78 87 config VIDEOBUF_GEN 79 88 tristate
+1
drivers/media/v4l2-core/Makefile
··· 25 25 # (e. g. LC_ALL=C sort Makefile) 26 26 27 27 obj-$(CONFIG_V4L2_ASYNC) += v4l2-async.o 28 + obj-$(CONFIG_V4L2_CCI) += v4l2-cci.o 28 29 obj-$(CONFIG_V4L2_FLASH_LED_CLASS) += v4l2-flash-led-class.o 29 30 obj-$(CONFIG_V4L2_FWNODE) += v4l2-fwnode.o 30 31 obj-$(CONFIG_V4L2_H264) += v4l2-h264.o
+166
drivers/media/v4l2-core/v4l2-cci.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * MIPI Camera Control Interface (CCI) register access helpers. 4 + * 5 + * Copyright (C) 2023 Hans de Goede <hansg@kernel.org> 6 + */ 7 + 8 + #include <linux/bitfield.h> 9 + #include <linux/delay.h> 10 + #include <linux/dev_printk.h> 11 + #include <linux/module.h> 12 + #include <linux/regmap.h> 13 + #include <linux/types.h> 14 + 15 + #include <asm/unaligned.h> 16 + 17 + #include <media/v4l2-cci.h> 18 + 19 + int cci_read(struct regmap *map, u32 reg, u64 *val, int *err) 20 + { 21 + unsigned int len; 22 + u8 buf[8]; 23 + int ret; 24 + 25 + if (err && *err) 26 + return *err; 27 + 28 + len = FIELD_GET(CCI_REG_WIDTH_MASK, reg); 29 + reg = FIELD_GET(CCI_REG_ADDR_MASK, reg); 30 + 31 + ret = regmap_bulk_read(map, reg, buf, len); 32 + if (ret) { 33 + dev_err(regmap_get_device(map), "Error reading reg 0x%4x: %d\n", 34 + reg, ret); 35 + goto out; 36 + } 37 + 38 + switch (len) { 39 + case 1: 40 + *val = buf[0]; 41 + break; 42 + case 2: 43 + *val = get_unaligned_be16(buf); 44 + break; 45 + case 3: 46 + *val = get_unaligned_be24(buf); 47 + break; 48 + case 4: 49 + *val = get_unaligned_be32(buf); 50 + break; 51 + case 8: 52 + *val = get_unaligned_be64(buf); 53 + break; 54 + default: 55 + dev_err(regmap_get_device(map), "Error invalid reg-width %u for reg 0x%04x\n", 56 + len, reg); 57 + ret = -EINVAL; 58 + break; 59 + } 60 + 61 + out: 62 + if (ret && err) 63 + *err = ret; 64 + 65 + return ret; 66 + } 67 + EXPORT_SYMBOL_GPL(cci_read); 68 + 69 + int cci_write(struct regmap *map, u32 reg, u64 val, int *err) 70 + { 71 + unsigned int len; 72 + u8 buf[8]; 73 + int ret; 74 + 75 + if (err && *err) 76 + return *err; 77 + 78 + len = FIELD_GET(CCI_REG_WIDTH_MASK, reg); 79 + reg = FIELD_GET(CCI_REG_ADDR_MASK, reg); 80 + 81 + switch (len) { 82 + case 1: 83 + buf[0] = val; 84 + break; 85 + case 2: 86 + put_unaligned_be16(val, buf); 87 + break; 88 + case 3: 89 + put_unaligned_be24(val, buf); 90 + break; 91 + case 4: 92 + put_unaligned_be32(val, buf); 93 + break; 94 + case 8: 95 + put_unaligned_be64(val, buf); 96 + break; 97 + default: 98 + dev_err(regmap_get_device(map), "Error invalid reg-width %u for reg 0x%04x\n", 99 + len, reg); 100 + ret = -EINVAL; 101 + goto out; 102 + } 103 + 104 + ret = regmap_bulk_write(map, reg, buf, len); 105 + if (ret) 106 + dev_err(regmap_get_device(map), "Error writing reg 0x%4x: %d\n", 107 + reg, ret); 108 + 109 + out: 110 + if (ret && err) 111 + *err = ret; 112 + 113 + return ret; 114 + } 115 + EXPORT_SYMBOL_GPL(cci_write); 116 + 117 + int cci_update_bits(struct regmap *map, u32 reg, u64 mask, u64 val, int *err) 118 + { 119 + u64 readval; 120 + int ret; 121 + 122 + ret = cci_read(map, reg, &readval, err); 123 + if (ret) 124 + return ret; 125 + 126 + val = (readval & ~mask) | (val & mask); 127 + 128 + return cci_write(map, reg, val, err); 129 + } 130 + EXPORT_SYMBOL_GPL(cci_update_bits); 131 + 132 + int cci_multi_reg_write(struct regmap *map, const struct cci_reg_sequence *regs, 133 + unsigned int num_regs, int *err) 134 + { 135 + unsigned int i; 136 + int ret; 137 + 138 + for (i = 0; i < num_regs; i++) { 139 + ret = cci_write(map, regs[i].reg, regs[i].val, err); 140 + if (ret) 141 + return ret; 142 + } 143 + 144 + return 0; 145 + } 146 + EXPORT_SYMBOL_GPL(cci_multi_reg_write); 147 + 148 + #if IS_ENABLED(CONFIG_V4L2_CCI_I2C) 149 + struct regmap *devm_cci_regmap_init_i2c(struct i2c_client *client, 150 + int reg_addr_bits) 151 + { 152 + struct regmap_config config = { 153 + .reg_bits = reg_addr_bits, 154 + .val_bits = 8, 155 + .reg_format_endian = REGMAP_ENDIAN_BIG, 156 + .disable_locking = true, 157 + }; 158 + 159 + return devm_regmap_init_i2c(client, &config); 160 + } 161 + EXPORT_SYMBOL_GPL(devm_cci_regmap_init_i2c); 162 + #endif 163 + 164 + MODULE_LICENSE("GPL"); 165 + MODULE_AUTHOR("Hans de Goede <hansg@kernel.org>"); 166 + MODULE_DESCRIPTION("MIPI Camera Control Interface (CCI) support");
+125
include/media/v4l2-cci.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * MIPI Camera Control Interface (CCI) register access helpers. 4 + * 5 + * Copyright (C) 2023 Hans de Goede <hansg@kernel.org> 6 + */ 7 + #ifndef _V4L2_CCI_H 8 + #define _V4L2_CCI_H 9 + 10 + #include <linux/types.h> 11 + 12 + struct i2c_client; 13 + struct regmap; 14 + 15 + /** 16 + * struct cci_reg_sequence - An individual write from a sequence of CCI writes 17 + * 18 + * @reg: Register address, use CCI_REG#() macros to encode reg width 19 + * @val: Register value 20 + * 21 + * Register/value pairs for sequences of writes. 22 + */ 23 + struct cci_reg_sequence { 24 + u32 reg; 25 + u64 val; 26 + }; 27 + 28 + /* 29 + * Macros to define register address with the register width encoded 30 + * into the higher bits. 31 + */ 32 + #define CCI_REG_ADDR_MASK GENMASK(15, 0) 33 + #define CCI_REG_WIDTH_SHIFT 16 34 + #define CCI_REG_WIDTH_MASK GENMASK(19, 16) 35 + 36 + #define CCI_REG8(x) ((1 << CCI_REG_WIDTH_SHIFT) | (x)) 37 + #define CCI_REG16(x) ((2 << CCI_REG_WIDTH_SHIFT) | (x)) 38 + #define CCI_REG24(x) ((3 << CCI_REG_WIDTH_SHIFT) | (x)) 39 + #define CCI_REG32(x) ((4 << CCI_REG_WIDTH_SHIFT) | (x)) 40 + #define CCI_REG64(x) ((8 << CCI_REG_WIDTH_SHIFT) | (x)) 41 + 42 + /** 43 + * cci_read() - Read a value from a single CCI register 44 + * 45 + * @map: Register map to read from 46 + * @reg: Register address to read, use CCI_REG#() macros to encode reg width 47 + * @val: Pointer to store read value 48 + * @err: Optional pointer to store errors, if a previous error is set 49 + * then the read will be skipped 50 + * 51 + * Return: %0 on success or a negative error code on failure. 52 + */ 53 + int cci_read(struct regmap *map, u32 reg, u64 *val, int *err); 54 + 55 + /** 56 + * cci_write() - Write a value to a single CCI register 57 + * 58 + * @map: Register map to write to 59 + * @reg: Register address to write, use CCI_REG#() macros to encode reg width 60 + * @val: Value to be written 61 + * @err: Optional pointer to store errors, if a previous error is set 62 + * then the write will be skipped 63 + * 64 + * Return: %0 on success or a negative error code on failure. 65 + */ 66 + int cci_write(struct regmap *map, u32 reg, u64 val, int *err); 67 + 68 + /** 69 + * cci_update_bits() - Perform a read/modify/write cycle on 70 + * a single CCI register 71 + * 72 + * @map: Register map to update 73 + * @reg: Register address to update, use CCI_REG#() macros to encode reg width 74 + * @mask: Bitmask to change 75 + * @val: New value for bitmask 76 + * @err: Optional pointer to store errors, if a previous error is set 77 + * then the update will be skipped 78 + * 79 + * Note this uses read-modify-write to update the bits, atomicity with regards 80 + * to other cci_*() register access functions is NOT guaranteed. 81 + * 82 + * Return: %0 on success or a negative error code on failure. 83 + */ 84 + int cci_update_bits(struct regmap *map, u32 reg, u64 mask, u64 val, int *err); 85 + 86 + /** 87 + * cci_multi_reg_write() - Write multiple registers to the device 88 + * 89 + * @map: Register map to write to 90 + * @regs: Array of structures containing register-address, -value pairs to be 91 + * written, register-addresses use CCI_REG#() macros to encode reg width 92 + * @num_regs: Number of registers to write 93 + * @err: Optional pointer to store errors, if a previous error is set 94 + * then the write will be skipped 95 + * 96 + * Write multiple registers to the device where the set of register, value 97 + * pairs are supplied in any order, possibly not all in a single range. 98 + * 99 + * Use of the CCI_REG#() macros to encode reg width is mandatory. 100 + * 101 + * For raw lists of register-address, -value pairs with only 8 bit 102 + * wide writes regmap_multi_reg_write() can be used instead. 103 + * 104 + * Return: %0 on success or a negative error code on failure. 105 + */ 106 + int cci_multi_reg_write(struct regmap *map, const struct cci_reg_sequence *regs, 107 + unsigned int num_regs, int *err); 108 + 109 + #if IS_ENABLED(CONFIG_V4L2_CCI_I2C) 110 + /** 111 + * devm_cci_regmap_init_i2c() - Create regmap to use with cci_*() register 112 + * access functions 113 + * 114 + * @client: i2c_client to create the regmap for 115 + * @reg_addr_bits: register address width to use (8 or 16) 116 + * 117 + * Note the memory for the created regmap is devm() managed, tied to the client. 118 + * 119 + * Return: %0 on success or a negative error code on failure. 120 + */ 121 + struct regmap *devm_cci_regmap_init_i2c(struct i2c_client *client, 122 + int reg_addr_bits); 123 + #endif 124 + 125 + #endif