summaryrefslogtreecommitdiff
path: root/include/media/v4l2-cci.h
blob: 4e96e90ee6369f14b43e012cd7044d14bcc5a7f0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
/* 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/bitfield.h>
#include <linux/bits.h>
#include <linux/types.h>

struct i2c_client;
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)
/*
 * Private CCI register flags, for the use of drivers.
 */
#define CCI_REG_PRIVATE_SHIFT		28U
#define CCI_REG_PRIVATE_MASK		GENMASK(31U, CCI_REG_PRIVATE_SHIFT)

#define CCI_REG_WIDTH_BYTES(x)		FIELD_GET(CCI_REG_WIDTH_MASK, x)
#define CCI_REG_WIDTH(x)		(CCI_REG_WIDTH_BYTES(x) << 3)
#define CCI_REG_ADDR(x)			FIELD_GET(CCI_REG_ADDR_MASK, x)
#define CCI_REG_LE			BIT(20)

#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))
#define CCI_REG16_LE(x)			(CCI_REG_LE | (2U << CCI_REG_WIDTH_SHIFT) | (x))
#define CCI_REG24_LE(x)			(CCI_REG_LE | (3U << CCI_REG_WIDTH_SHIFT) | (x))
#define CCI_REG32_LE(x)			(CCI_REG_LE | (4U << CCI_REG_WIDTH_SHIFT) | (x))
#define CCI_REG64_LE(x)			(CCI_REG_LE | (8U << 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
 *       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 with regards
 * to other 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,
			unsigned int num_regs, int *err);

#if IS_ENABLED(CONFIG_V4L2_CCI_I2C)
/**
 * devm_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 *devm_cci_regmap_init_i2c(struct i2c_client *client,
					int reg_addr_bits);
#endif

#endif