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