brintos

brintos / linux-shallow public Read only

0
0
Text · 4.0 KiB · e9ecf47 Raw
204 lines · c
1// SPDX-License-Identifier: GPL-2.02/*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 <linux/unaligned.h>16 17#include <media/v4l2-cci.h>18 19int cci_read(struct regmap *map, u32 reg, u64 *val, int *err)20{21	bool little_endian;22	unsigned int len;23	u8 buf[8];24	int ret;25 26	/*27	 * TODO: Fix smatch. Assign *val to 0 here in order to avoid28	 * failing a smatch check on caller when the caller proceeds to29	 * read *val without initialising it on caller's side. *val is set30	 * to a valid value whenever this function returns 0 but smatch31	 * can't figure that out currently.32	 */33	*val = 0;34 35	if (err && *err)36		return *err;37 38	little_endian = reg & CCI_REG_LE;39	len = CCI_REG_WIDTH_BYTES(reg);40	reg = CCI_REG_ADDR(reg);41 42	ret = regmap_bulk_read(map, reg, buf, len);43	if (ret) {44		dev_err(regmap_get_device(map), "Error reading reg 0x%04x: %d\n",45			reg, ret);46		goto out;47	}48 49	switch (len) {50	case 1:51		*val = buf[0];52		break;53	case 2:54		if (little_endian)55			*val = get_unaligned_le16(buf);56		else57			*val = get_unaligned_be16(buf);58		break;59	case 3:60		if (little_endian)61			*val = get_unaligned_le24(buf);62		else63			*val = get_unaligned_be24(buf);64		break;65	case 4:66		if (little_endian)67			*val = get_unaligned_le32(buf);68		else69			*val = get_unaligned_be32(buf);70		break;71	case 8:72		if (little_endian)73			*val = get_unaligned_le64(buf);74		else75			*val = get_unaligned_be64(buf);76		break;77	default:78		dev_err(regmap_get_device(map), "Error invalid reg-width %u for reg 0x%04x\n",79			len, reg);80		ret = -EINVAL;81		break;82	}83 84out:85	if (ret && err)86		*err = ret;87 88	return ret;89}90EXPORT_SYMBOL_GPL(cci_read);91 92int cci_write(struct regmap *map, u32 reg, u64 val, int *err)93{94	bool little_endian;95	unsigned int len;96	u8 buf[8];97	int ret;98 99	if (err && *err)100		return *err;101 102	little_endian = reg & CCI_REG_LE;103	len = CCI_REG_WIDTH_BYTES(reg);104	reg = CCI_REG_ADDR(reg);105 106	switch (len) {107	case 1:108		buf[0] = val;109		break;110	case 2:111		if (little_endian)112			put_unaligned_le16(val, buf);113		else114			put_unaligned_be16(val, buf);115		break;116	case 3:117		if (little_endian)118			put_unaligned_le24(val, buf);119		else120			put_unaligned_be24(val, buf);121		break;122	case 4:123		if (little_endian)124			put_unaligned_le32(val, buf);125		else126			put_unaligned_be32(val, buf);127		break;128	case 8:129		if (little_endian)130			put_unaligned_le64(val, buf);131		else132			put_unaligned_be64(val, buf);133		break;134	default:135		dev_err(regmap_get_device(map), "Error invalid reg-width %u for reg 0x%04x\n",136			len, reg);137		ret = -EINVAL;138		goto out;139	}140 141	ret = regmap_bulk_write(map, reg, buf, len);142	if (ret)143		dev_err(regmap_get_device(map), "Error writing reg 0x%04x: %d\n",144			reg, ret);145 146out:147	if (ret && err)148		*err = ret;149 150	return ret;151}152EXPORT_SYMBOL_GPL(cci_write);153 154int cci_update_bits(struct regmap *map, u32 reg, u64 mask, u64 val, int *err)155{156	u64 readval;157	int ret;158 159	ret = cci_read(map, reg, &readval, err);160	if (ret)161		return ret;162 163	val = (readval & ~mask) | (val & mask);164 165	return cci_write(map, reg, val, err);166}167EXPORT_SYMBOL_GPL(cci_update_bits);168 169int cci_multi_reg_write(struct regmap *map, const struct cci_reg_sequence *regs,170			unsigned int num_regs, int *err)171{172	unsigned int i;173	int ret;174 175	for (i = 0; i < num_regs; i++) {176		ret = cci_write(map, regs[i].reg, regs[i].val, err);177		if (ret)178			return ret;179	}180 181	return 0;182}183EXPORT_SYMBOL_GPL(cci_multi_reg_write);184 185#if IS_ENABLED(CONFIG_V4L2_CCI_I2C)186struct regmap *devm_cci_regmap_init_i2c(struct i2c_client *client,187					int reg_addr_bits)188{189	struct regmap_config config = {190		.reg_bits = reg_addr_bits,191		.val_bits = 8,192		.reg_format_endian = REGMAP_ENDIAN_BIG,193		.disable_locking = true,194	};195 196	return devm_regmap_init_i2c(client, &config);197}198EXPORT_SYMBOL_GPL(devm_cci_regmap_init_i2c);199#endif200 201MODULE_LICENSE("GPL");202MODULE_AUTHOR("Hans de Goede <hansg@kernel.org>");203MODULE_DESCRIPTION("MIPI Camera Control Interface (CCI) support");204