xref: /optee_os/core/include/drivers/i2c.h (revision 12fc37711783247b0d05fdc271ef007f4930767b)
1 /* SPDX-License-Identifier: BSD-2-Clause */
2 /*
3  * Copyright (c) 2022, Microchip
4  */
5 
6 #ifndef __DRIVERS_I2C_H
7 #define __DRIVERS_I2C_H
8 
9 #include <kernel/dt_driver.h>
10 #include <libfdt.h>
11 #include <tee_api_types.h>
12 
13 /**
14  * DEFINE_I2C_DEV_DRIVER - Declare an I2C driver
15  *
16  * @__name: I2C device driver name
17  * @__match_table: match table associated to the driver
18  * @__i2c_probe: I2C probe function with the following prototype:
19  *	TEE_Result (*probe)(struct i2c_dev *i2c_dev, const void *fdt,
20  *			    int node, const void *compat_data);
21  */
22 #define DEFINE_I2C_DEV_DRIVER(__name, __match_table, __i2c_probe) \
23 	static TEE_Result __name ## _probe_i2c_dev(const void *fdt, int node, \
24 						   const void *compat_data) \
25 	{ \
26 		struct i2c_dev *i2c_dev = NULL; \
27 		TEE_Result res = TEE_ERROR_GENERIC; \
28 		\
29 		res = i2c_dt_get_dev(fdt, node, &i2c_dev); \
30 		if (res) \
31 			return res; \
32 		return __i2c_probe(i2c_dev, fdt, node, compat_data); \
33 	} \
34 	DEFINE_DT_DRIVER(__name ## _dt_driver) = { \
35 		.name = # __name, \
36 		.type = DT_DRIVER_I2C, \
37 		.match_table = __match_table, \
38 		.probe = __name ## _probe_i2c_dev, \
39 	}
40 
41 #define I2C_SMBUS_MAX_BUF_SIZE	32
42 
43 enum i2c_smbus_dir {
44 	I2C_SMBUS_READ,
45 	I2C_SMBUS_WRITE,
46 };
47 
48 enum i2c_smbus_protocol {
49 	I2C_SMBUS_PROTO_BYTE,
50 	/*
51 	 * Like block but does not insert "count" in sent data, useful for
52 	 * EEPROM read for instance which is not SMBus but requires such
53 	 * sequence.
54 	 */
55 	I2C_SMBUS_PROTO_BLOCK_RAW,
56 };
57 
58 struct i2c_ctrl;
59 
60 /**
61  * struct i2c_dev - I2C device
62  *
63  * @ctrl: I2C controller associated to the device
64  * @addr: device address on the I2C bus
65  */
66 struct i2c_dev {
67 	struct i2c_ctrl *ctrl;
68 	uint16_t addr;
69 };
70 
71 /**
72  * struct i2c_ctrl_ops - Operations provided by I2C controller drivers
73  *
74  * @read: I2C read operation
75  * @write: I2C write operation
76  * @smbus: SMBus protocol operation
77  */
78 struct i2c_ctrl_ops {
79 	TEE_Result (*read)(struct i2c_dev *i2c_dev, uint8_t *buf, size_t len);
80 	TEE_Result (*write)(struct i2c_dev *i2c_dev, const uint8_t *buf,
81 			    size_t len);
82 	TEE_Result (*smbus)(struct i2c_dev *i2c_dev, enum i2c_smbus_dir dir,
83 			    enum i2c_smbus_protocol proto, uint8_t cmd_code,
84 			    uint8_t *buf, size_t len);
85 };
86 
87 /**
88  * struct i2c_ctrl - I2C controller
89  *
90  * @ops: Operations associated to the I2C controller
91  */
92 struct i2c_ctrl {
93 	const struct i2c_ctrl_ops *ops;
94 };
95 
96 #ifdef CFG_DRIVERS_I2C
97 /**
98  * i2c_create_dev - Create and i2c_dev struct from device-tree
99  *
100  * @i2c_ctrl: Controller to be used with this device
101  * @fdt: Device-tree to work on
102  * @node: Node to work on in @fdt provided device-tree
103  *
104  * Return an i2c_dev struct filled from device-tree description
105  */
106 struct i2c_dev *i2c_create_dev(struct i2c_ctrl *i2c_ctrl, const void *fdt,
107 			       int node);
108 
109 /**
110  * i2c_write() - Execute an I2C write on the I2C bus
111  *
112  * @i2c_dev: I2C device used for writing
113  * @buf: Buffer of data to be written
114  * @len: Length of data to be written
115  *
116  * Return a TEE_Result compliant value
117  */
118 static inline TEE_Result i2c_write(struct i2c_dev *i2c_dev, const uint8_t *buf,
119 				   size_t len)
120 {
121 	if (!i2c_dev->ctrl->ops->write)
122 		return TEE_ERROR_NOT_SUPPORTED;
123 
124 	return i2c_dev->ctrl->ops->write(i2c_dev, buf, len);
125 }
126 
127 /**
128  * i2c_read() - Execute an I2C read on the I2C bus
129  *
130  * @i2c_dev: I2C device used for reading
131  * @buf: Buffer containing the read data
132  * @len: Length of data to be read
133  *
134  * Return a TEE_Result compliant value
135  */
136 static inline TEE_Result i2c_read(struct i2c_dev *i2c_dev, uint8_t *buf,
137 				  size_t len)
138 {
139 	if (!i2c_dev->ctrl->ops->read)
140 		return TEE_ERROR_NOT_SUPPORTED;
141 
142 	return i2c_dev->ctrl->ops->read(i2c_dev, buf, len);
143 }
144 
145 /**
146  * i2c_smbus_raw() - Execute a raw SMBUS request
147  *
148  * @i2c_dev: I2C device used for SMBus operation
149  * @dir: Direction for the SMBus transfer
150  * @proto: SMBus Protocol to be executed
151  * @cmd_code: Command code
152  * @buf: Buffer used for read/write operation
153  * @len: Length of buffer to be read/write
154  *
155  * Return a TEE_Result compliant value
156  */
157 static inline TEE_Result i2c_smbus_raw(struct i2c_dev *i2c_dev,
158 				       enum i2c_smbus_dir dir,
159 				       enum i2c_smbus_protocol proto,
160 				       uint8_t cmd_code, uint8_t *buf,
161 				       size_t len)
162 {
163 	if (!i2c_dev->ctrl->ops->smbus)
164 		return TEE_ERROR_NOT_SUPPORTED;
165 
166 	if (len > I2C_SMBUS_MAX_BUF_SIZE)
167 		return TEE_ERROR_BAD_PARAMETERS;
168 
169 	return i2c_dev->ctrl->ops->smbus(i2c_dev, dir, proto, cmd_code, buf,
170 					 len);
171 }
172 
173 /**
174  * i2c_dt_get_dev - Get an I2C device from a DT node
175  *
176  * @fdt: Device tree to work on
177  * @nodeoffset: Node offset of the I2C bus consumer
178  * @i2c_dev: Output I2C bus device upon success
179  *
180  * Return TEE_SUCCESS in case of success
181  * Return TEE_ERROR_DEFER_DRIVER_INIT if I2C controller is not initialized
182  * Return TEE_ERROR_ITEM_NOT_FOUND if the I2C controller node does not exist
183  * Return a TEE_Result compliant code in case of error
184  */
185 static inline TEE_Result i2c_dt_get_dev(const void *fdt, int nodeoffset,
186 					struct i2c_dev **i2c_dev)
187 {
188 	TEE_Result res = TEE_ERROR_GENERIC;
189 
190 	*i2c_dev = dt_driver_device_from_parent(fdt, nodeoffset, DT_DRIVER_I2C,
191 						&res);
192 	return res;
193 }
194 #else
195 static inline TEE_Result i2c_write(struct i2c_dev *i2c_dev __unused,
196 				   const uint8_t *buf __unused,
197 				   size_t len __unused)
198 {
199 	return TEE_ERROR_NOT_SUPPORTED;
200 }
201 
202 static inline TEE_Result i2c_read(struct i2c_dev *i2c_dev __unused,
203 				  uint8_t *buf __unused, size_t len __unused)
204 {
205 	return TEE_ERROR_NOT_SUPPORTED;
206 }
207 
208 static inline TEE_Result i2c_smbus_raw(struct i2c_dev *i2c_dev __unused,
209 				       enum i2c_smbus_dir dir __unused,
210 				       enum i2c_smbus_protocol proto __unused,
211 				       uint8_t cmd_code __unused,
212 				       uint8_t *buf __unused,
213 				       size_t len __unused)
214 {
215 	return TEE_ERROR_NOT_SUPPORTED;
216 }
217 
218 static inline TEE_Result i2c_dt_get_dev(const void *fdt __unused,
219 					int nodeoffset __unused,
220 					struct i2c_dev **i2c_dev)
221 {
222 	*i2c_dev = NULL;
223 	return TEE_ERROR_NOT_SUPPORTED;
224 }
225 #endif
226 
227 /**
228  * i2c_dt_get_func - Typedef of function to get I2C bus device from
229  * devicetree properties
230  *
231  * @args: Pointer to devicetree description of the I2C bus device to parse
232  * @data: Pointer to data given at i2c_dt_register_provider() call
233  * @res: Output result code of the operation:
234  *	TEE_SUCCESS in case of success
235  *	TEE_ERROR_DEFER_DRIVER_INIT if I2C controller is not initialized
236  *	Any TEE_Result compliant code in case of error.
237  *
238  * Returns a struct i2c pointer pointing to a I2C bus device matching
239  * the devicetree description or NULL if invalid description in which case
240  * @res provides the error code.
241  */
242 typedef struct i2c_dev *(*i2c_dt_get_func)(struct dt_pargs *args, void *data,
243 					   TEE_Result *res);
244 
245 /**
246  * i2c_dt_register_provider - Register a I2C controller provider and add all the
247  *	child nodes of this controller in the DT probe list.
248  *
249  * @fdt: Device tree to work on
250  * @nodeoffset: Node offset of the I2C controller
251  * @get_dt_i2c: Callback to match the I2C controller with a struct i2c
252  * @data: Data which will be passed to the get_dt_i2c callback
253  * Returns TEE_Result value
254  */
255 static inline
256 TEE_Result i2c_register_provider(const void *fdt, int nodeoffset,
257 				 i2c_dt_get_func get_dt_i2c, void *data)
258 {
259 	int subnode = -1;
260 	TEE_Result res = TEE_ERROR_GENERIC;
261 
262 	res = dt_driver_register_provider(fdt, nodeoffset,
263 					  (get_of_device_func)get_dt_i2c,
264 					  data, DT_DRIVER_I2C);
265 	if (res)
266 		return res;
267 
268 	fdt_for_each_subnode(subnode, fdt, nodeoffset)
269 		dt_driver_maybe_add_probe_node(fdt, subnode);
270 
271 	return TEE_SUCCESS;
272 }
273 
274 /**
275  * i2c_smbus_read_byte_data() - Execute a read byte SMBus protocol operation
276  *
277  * @i2c_dev: I2C device used for SMBus operation
278  * @cmd_code: Command code to read
279  * @byte: Returned byte value read from device
280  *
281  * Return a TEE_Result compliant value
282  */
283 static inline TEE_Result i2c_smbus_read_byte_data(struct i2c_dev *i2c_dev,
284 						  uint8_t cmd_code,
285 						  uint8_t *byte)
286 {
287 	return i2c_smbus_raw(i2c_dev, I2C_SMBUS_READ, I2C_SMBUS_PROTO_BYTE,
288 			     cmd_code, byte, 1);
289 }
290 
291 /**
292  * i2c_smbus_write_byte_data() - Execute a write byte SMBus protocol operation
293  *
294  * @i2c_dev: I2C device used for SMBus operation
295  * @cmd_code: Command code for write operation
296  * @byte: Byte to be written to the device
297  *
298  * Return a TEE_Result compliant value
299  */
300 static inline TEE_Result i2c_smbus_write_byte_data(struct i2c_dev *i2c_dev,
301 						   uint8_t cmd_code,
302 						   uint8_t byte)
303 {
304 	return i2c_smbus_raw(i2c_dev, I2C_SMBUS_WRITE, I2C_SMBUS_PROTO_BYTE,
305 			     cmd_code, &byte, 1);
306 }
307 
308 /**
309  * i2c_bus_read_block_raw() - Execute a non-standard SMBus raw block read.
310  * This does not insert the "count" of byte to be written unlike the SMBus block
311  * read operation.
312  *
313  * @i2c_dev: I2C device used for SMBus operation
314  * @cmd_code: Command code for read operation
315  * @buf: Buffer of data read from device
316  * @len: Length of data to be read from the device
317  *
318  * Return a TEE_Result compliant value
319  */
320 static inline TEE_Result i2c_bus_read_block_raw(struct i2c_dev *i2c_dev,
321 						uint8_t cmd_code, uint8_t *buf,
322 						size_t len)
323 {
324 	return i2c_smbus_raw(i2c_dev, I2C_SMBUS_READ, I2C_SMBUS_PROTO_BLOCK_RAW,
325 			     cmd_code, buf, len);
326 }
327 
328 /**
329  * i2c_bus_write_block_raw() - Execute a non-standard SMBus raw block write.
330  * This does not insert the "count" of byte to be written unlike the SMBus block
331  * write operation.
332  *
333  * @i2c_dev: I2C device used for SMBus operation
334  * @cmd_code: Command code for write operation
335  * @buf: Buffer of data to be written to the device
336  * @len: Length of data to be written to the device
337  *
338  * Return a TEE_Result compliant value
339  */
340 static inline TEE_Result i2c_bus_write_block_raw(struct i2c_dev *i2c_dev,
341 						 uint8_t cmd_code,
342 						 uint8_t *buf, size_t len)
343 {
344 	return i2c_smbus_raw(i2c_dev, I2C_SMBUS_WRITE,
345 			     I2C_SMBUS_PROTO_BLOCK_RAW, cmd_code, buf, len);
346 }
347 
348 #endif
349