From ace9429bb58fd418f0c81d4c2835699bddf6bde6 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Thu, 11 Apr 2024 10:27:49 +0200 Subject: Adding upstream version 6.6.15. Signed-off-by: Daniel Baumann --- drivers/media/v4l2-core/v4l2-cci.c | 194 +++++++++++++++++++++++++++++++++++++ 1 file changed, 194 insertions(+) create mode 100644 drivers/media/v4l2-core/v4l2-cci.c (limited to 'drivers/media/v4l2-core/v4l2-cci.c') diff --git a/drivers/media/v4l2-core/v4l2-cci.c b/drivers/media/v4l2-core/v4l2-cci.c new file mode 100644 index 000000000..10005c80f --- /dev/null +++ b/drivers/media/v4l2-core/v4l2-cci.c @@ -0,0 +1,194 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * MIPI Camera Control Interface (CCI) register access helpers. + * + * Copyright (C) 2023 Hans de Goede + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include + +int cci_read(struct regmap *map, u32 reg, u64 *val, int *err) +{ + bool little_endian; + unsigned int len; + u8 buf[8]; + int ret; + + if (err && *err) + return *err; + + little_endian = reg & CCI_REG_LE; + len = CCI_REG_WIDTH_BYTES(reg); + reg = CCI_REG_ADDR(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: + if (little_endian) + *val = get_unaligned_le16(buf); + else + *val = get_unaligned_be16(buf); + break; + case 3: + if (little_endian) + *val = get_unaligned_le24(buf); + else + *val = get_unaligned_be24(buf); + break; + case 4: + if (little_endian) + *val = get_unaligned_le32(buf); + else + *val = get_unaligned_be32(buf); + break; + case 8: + if (little_endian) + *val = get_unaligned_le64(buf); + else + *val = get_unaligned_be64(buf); + break; + default: + dev_err(regmap_get_device(map), "Error invalid reg-width %u 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) +{ + bool little_endian; + unsigned int len; + u8 buf[8]; + int ret; + + if (err && *err) + return *err; + + little_endian = reg & CCI_REG_LE; + len = CCI_REG_WIDTH_BYTES(reg); + reg = CCI_REG_ADDR(reg); + + switch (len) { + case 1: + buf[0] = val; + break; + case 2: + if (little_endian) + put_unaligned_le16(val, buf); + else + put_unaligned_be16(val, buf); + break; + case 3: + if (little_endian) + put_unaligned_le24(val, buf); + else + put_unaligned_be24(val, buf); + break; + case 4: + if (little_endian) + put_unaligned_le32(val, buf); + else + put_unaligned_be32(val, buf); + break; + case 8: + if (little_endian) + put_unaligned_le64(val, buf); + else + put_unaligned_be64(val, buf); + break; + default: + dev_err(regmap_get_device(map), "Error invalid reg-width %u 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, + unsigned int num_regs, int *err) +{ + unsigned int i; + int 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); + +#if IS_ENABLED(CONFIG_V4L2_CCI_I2C) +struct regmap *devm_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(devm_cci_regmap_init_i2c); +#endif + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Hans de Goede "); +MODULE_DESCRIPTION("MIPI Camera Control Interface (CCI) support"); -- cgit v1.2.3