18bc9c9e2SClément Léger /* SPDX-License-Identifier: BSD-2-Clause */ 28bc9c9e2SClément Léger /* 38bc9c9e2SClément Léger * Copyright (c) 2022, Microchip 48bc9c9e2SClément Léger */ 58bc9c9e2SClément Léger 68bc9c9e2SClément Léger #ifndef __DRIVERS_I2C_H 78bc9c9e2SClément Léger #define __DRIVERS_I2C_H 88bc9c9e2SClément Léger 98bc9c9e2SClément Léger #include <kernel/dt_driver.h> 108bc9c9e2SClément Léger #include <libfdt.h> 118bc9c9e2SClément Léger #include <tee_api_types.h> 128bc9c9e2SClément Léger 138bc9c9e2SClément Léger /** 148bc9c9e2SClément Léger * DEFINE_I2C_DEV_DRIVER - Declare an I2C driver 158bc9c9e2SClément Léger * 168bc9c9e2SClément Léger * @__name: I2C device driver name 178bc9c9e2SClément Léger * @__match_table: match table associated to the driver 188bc9c9e2SClément Léger * @__i2c_probe: I2C probe function with the following prototype: 198bc9c9e2SClément Léger * TEE_Result (*probe)(struct i2c_dev *i2c_dev, const void *fdt, 208bc9c9e2SClément Léger * int node, const void *compat_data); 218bc9c9e2SClément Léger */ 228bc9c9e2SClément Léger #define DEFINE_I2C_DEV_DRIVER(__name, __match_table, __i2c_probe) \ 238bc9c9e2SClément Léger static TEE_Result __name ## _probe_i2c_dev(const void *fdt, int node, \ 248bc9c9e2SClément Léger const void *compat_data) \ 258bc9c9e2SClément Léger { \ 268bc9c9e2SClément Léger struct i2c_dev *i2c_dev = NULL; \ 278bc9c9e2SClément Léger TEE_Result res = TEE_ERROR_GENERIC; \ 288bc9c9e2SClément Léger \ 298bc9c9e2SClément Léger res = i2c_dt_get_dev(fdt, node, &i2c_dev); \ 308bc9c9e2SClément Léger if (res) \ 318bc9c9e2SClément Léger return res; \ 328bc9c9e2SClément Léger return __i2c_probe(i2c_dev, fdt, node, compat_data); \ 338bc9c9e2SClément Léger } \ 348bc9c9e2SClément Léger DEFINE_DT_DRIVER(__name ## _dt_driver) = { \ 358bc9c9e2SClément Léger .name = # __name, \ 368bc9c9e2SClément Léger .type = DT_DRIVER_I2C, \ 378bc9c9e2SClément Léger .match_table = __match_table, \ 388bc9c9e2SClément Léger .probe = __name ## _probe_i2c_dev, \ 398bc9c9e2SClément Léger } 408bc9c9e2SClément Léger 418bc9c9e2SClément Léger #define I2C_SMBUS_MAX_BUF_SIZE 32 428bc9c9e2SClément Léger 438bc9c9e2SClément Léger enum i2c_smbus_dir { 448bc9c9e2SClément Léger I2C_SMBUS_READ, 458bc9c9e2SClément Léger I2C_SMBUS_WRITE, 468bc9c9e2SClément Léger }; 478bc9c9e2SClément Léger 488bc9c9e2SClément Léger enum i2c_smbus_protocol { 498bc9c9e2SClément Léger I2C_SMBUS_PROTO_BYTE, 508bc9c9e2SClément Léger /* 518bc9c9e2SClément Léger * Like block but does not insert "count" in sent data, useful for 528bc9c9e2SClément Léger * EEPROM read for instance which is not SMBus but requires such 538bc9c9e2SClément Léger * sequence. 548bc9c9e2SClément Léger */ 558bc9c9e2SClément Léger I2C_SMBUS_PROTO_BLOCK_RAW, 568bc9c9e2SClément Léger }; 578bc9c9e2SClément Léger 588bc9c9e2SClément Léger struct i2c_ctrl; 598bc9c9e2SClément Léger 608bc9c9e2SClément Léger /** 618bc9c9e2SClément Léger * struct i2c_dev - I2C device 628bc9c9e2SClément Léger * 638bc9c9e2SClément Léger * @ctrl: I2C controller associated to the device 648bc9c9e2SClément Léger * @addr: device address on the I2C bus 658bc9c9e2SClément Léger */ 668bc9c9e2SClément Léger struct i2c_dev { 678bc9c9e2SClément Léger struct i2c_ctrl *ctrl; 688bc9c9e2SClément Léger uint16_t addr; 698bc9c9e2SClément Léger }; 708bc9c9e2SClément Léger 718bc9c9e2SClément Léger /** 728bc9c9e2SClément Léger * struct i2c_ctrl_ops - Operations provided by I2C controller drivers 738bc9c9e2SClément Léger * 748bc9c9e2SClément Léger * @read: I2C read operation 758bc9c9e2SClément Léger * @write: I2C write operation 768bc9c9e2SClément Léger * @smbus: SMBus protocol operation 778bc9c9e2SClément Léger */ 788bc9c9e2SClément Léger struct i2c_ctrl_ops { 798bc9c9e2SClément Léger TEE_Result (*read)(struct i2c_dev *i2c_dev, uint8_t *buf, size_t len); 808bc9c9e2SClément Léger TEE_Result (*write)(struct i2c_dev *i2c_dev, const uint8_t *buf, 818bc9c9e2SClément Léger size_t len); 828bc9c9e2SClément Léger TEE_Result (*smbus)(struct i2c_dev *i2c_dev, enum i2c_smbus_dir dir, 838bc9c9e2SClément Léger enum i2c_smbus_protocol proto, uint8_t cmd_code, 848bc9c9e2SClément Léger uint8_t *buf, size_t len); 858bc9c9e2SClément Léger }; 868bc9c9e2SClément Léger 878bc9c9e2SClément Léger /** 888bc9c9e2SClément Léger * struct i2c_ctrl - I2C controller 898bc9c9e2SClément Léger * 908bc9c9e2SClément Léger * @ops: Operations associated to the I2C controller 918bc9c9e2SClément Léger */ 928bc9c9e2SClément Léger struct i2c_ctrl { 938bc9c9e2SClément Léger const struct i2c_ctrl_ops *ops; 948bc9c9e2SClément Léger }; 958bc9c9e2SClément Léger 968bc9c9e2SClément Léger #ifdef CFG_DRIVERS_I2C 978bc9c9e2SClément Léger /** 988bc9c9e2SClément Léger * i2c_create_dev - Create and i2c_dev struct from device-tree 998bc9c9e2SClément Léger * 1008bc9c9e2SClément Léger * @i2c_ctrl: Controller to be used with this device 1018bc9c9e2SClément Léger * @fdt: Device-tree to work on 1028bc9c9e2SClément Léger * @node: Node to work on in @fdt provided device-tree 1038bc9c9e2SClément Léger * 1048bc9c9e2SClément Léger * Return an i2c_dev struct filled from device-tree description 1058bc9c9e2SClément Léger */ 1068bc9c9e2SClément Léger struct i2c_dev *i2c_create_dev(struct i2c_ctrl *i2c_ctrl, const void *fdt, 1078bc9c9e2SClément Léger int node); 1088bc9c9e2SClément Léger 1098bc9c9e2SClément Léger /** 1108bc9c9e2SClément Léger * i2c_write() - Execute an I2C write on the I2C bus 1118bc9c9e2SClément Léger * 1128bc9c9e2SClément Léger * @i2c_dev: I2C device used for writing 1138bc9c9e2SClément Léger * @buf: Buffer of data to be written 1148bc9c9e2SClément Léger * @len: Length of data to be written 1158bc9c9e2SClément Léger * 1168bc9c9e2SClément Léger * Return a TEE_Result compliant value 1178bc9c9e2SClément Léger */ 1188bc9c9e2SClément Léger static inline TEE_Result i2c_write(struct i2c_dev *i2c_dev, const uint8_t *buf, 1198bc9c9e2SClément Léger size_t len) 1208bc9c9e2SClément Léger { 1218bc9c9e2SClément Léger if (!i2c_dev->ctrl->ops->write) 1228bc9c9e2SClément Léger return TEE_ERROR_NOT_SUPPORTED; 1238bc9c9e2SClément Léger 1248bc9c9e2SClément Léger return i2c_dev->ctrl->ops->write(i2c_dev, buf, len); 1258bc9c9e2SClément Léger } 1268bc9c9e2SClément Léger 1278bc9c9e2SClément Léger /** 1288bc9c9e2SClément Léger * i2c_read() - Execute an I2C read on the I2C bus 1298bc9c9e2SClément Léger * 1308bc9c9e2SClément Léger * @i2c_dev: I2C device used for reading 1318bc9c9e2SClément Léger * @buf: Buffer containing the read data 1328bc9c9e2SClément Léger * @len: Length of data to be read 1338bc9c9e2SClément Léger * 1348bc9c9e2SClément Léger * Return a TEE_Result compliant value 1358bc9c9e2SClément Léger */ 1368bc9c9e2SClément Léger static inline TEE_Result i2c_read(struct i2c_dev *i2c_dev, uint8_t *buf, 1378bc9c9e2SClément Léger size_t len) 1388bc9c9e2SClément Léger { 1398bc9c9e2SClément Léger if (!i2c_dev->ctrl->ops->read) 1408bc9c9e2SClément Léger return TEE_ERROR_NOT_SUPPORTED; 1418bc9c9e2SClément Léger 1428bc9c9e2SClément Léger return i2c_dev->ctrl->ops->read(i2c_dev, buf, len); 1438bc9c9e2SClément Léger } 1448bc9c9e2SClément Léger 1458bc9c9e2SClément Léger /** 1468bc9c9e2SClément Léger * i2c_smbus_raw() - Execute a raw SMBUS request 1478bc9c9e2SClément Léger * 1488bc9c9e2SClément Léger * @i2c_dev: I2C device used for SMBus operation 1498bc9c9e2SClément Léger * @dir: Direction for the SMBus transfer 1508bc9c9e2SClément Léger * @proto: SMBus Protocol to be executed 1518bc9c9e2SClément Léger * @cmd_code: Command code 1528bc9c9e2SClément Léger * @buf: Buffer used for read/write operation 1538bc9c9e2SClément Léger * @len: Length of buffer to be read/write 1548bc9c9e2SClément Léger * 1558bc9c9e2SClément Léger * Return a TEE_Result compliant value 1568bc9c9e2SClément Léger */ 1578bc9c9e2SClément Léger static inline TEE_Result i2c_smbus_raw(struct i2c_dev *i2c_dev, 1588bc9c9e2SClément Léger enum i2c_smbus_dir dir, 1598bc9c9e2SClément Léger enum i2c_smbus_protocol proto, 1608bc9c9e2SClément Léger uint8_t cmd_code, uint8_t *buf, 1618bc9c9e2SClément Léger size_t len) 1628bc9c9e2SClément Léger { 1638bc9c9e2SClément Léger if (!i2c_dev->ctrl->ops->smbus) 1648bc9c9e2SClément Léger return TEE_ERROR_NOT_SUPPORTED; 1658bc9c9e2SClément Léger 1668bc9c9e2SClément Léger if (len > I2C_SMBUS_MAX_BUF_SIZE) 1678bc9c9e2SClément Léger return TEE_ERROR_BAD_PARAMETERS; 1688bc9c9e2SClément Léger 1698bc9c9e2SClément Léger return i2c_dev->ctrl->ops->smbus(i2c_dev, dir, proto, cmd_code, buf, 1708bc9c9e2SClément Léger len); 1718bc9c9e2SClément Léger } 1728bc9c9e2SClément Léger 1738bc9c9e2SClément Léger /** 1748bc9c9e2SClément Léger * i2c_dt_get_dev - Get an I2C device from a DT node 1758bc9c9e2SClément Léger * 1768bc9c9e2SClément Léger * @fdt: Device tree to work on 1778bc9c9e2SClément Léger * @nodeoffset: Node offset of the I2C bus consumer 1788bc9c9e2SClément Léger * @i2c_dev: Output I2C bus device upon success 1798bc9c9e2SClément Léger * 1808bc9c9e2SClément Léger * Return TEE_SUCCESS in case of success 1818bc9c9e2SClément Léger * Return TEE_ERROR_DEFER_DRIVER_INIT if I2C controller is not initialized 1828bc9c9e2SClément Léger * Return TEE_ERROR_ITEM_NOT_FOUND if the I2C controller node does not exist 1838bc9c9e2SClément Léger * Return a TEE_Result compliant code in case of error 1848bc9c9e2SClément Léger */ 1858bc9c9e2SClément Léger static inline TEE_Result i2c_dt_get_dev(const void *fdt, int nodeoffset, 186*b357d34fSEtienne Carriere struct i2c_dev **out_i2c_dev) 1878bc9c9e2SClément Léger { 1888bc9c9e2SClément Léger TEE_Result res = TEE_ERROR_GENERIC; 189*b357d34fSEtienne Carriere void *i2c_dev = NULL; 1908bc9c9e2SClément Léger 191*b357d34fSEtienne Carriere res = dt_driver_device_from_parent(fdt, nodeoffset, DT_DRIVER_I2C, 192*b357d34fSEtienne Carriere &i2c_dev); 193*b357d34fSEtienne Carriere if (!res) 194*b357d34fSEtienne Carriere *out_i2c_dev = i2c_dev; 195*b357d34fSEtienne Carriere 1968bc9c9e2SClément Léger return res; 1978bc9c9e2SClément Léger } 1988bc9c9e2SClément Léger #else 1998bc9c9e2SClément Léger static inline TEE_Result i2c_write(struct i2c_dev *i2c_dev __unused, 2008bc9c9e2SClément Léger const uint8_t *buf __unused, 2018bc9c9e2SClément Léger size_t len __unused) 2028bc9c9e2SClément Léger { 2038bc9c9e2SClément Léger return TEE_ERROR_NOT_SUPPORTED; 2048bc9c9e2SClément Léger } 2058bc9c9e2SClément Léger 2068bc9c9e2SClément Léger static inline TEE_Result i2c_read(struct i2c_dev *i2c_dev __unused, 2078bc9c9e2SClément Léger uint8_t *buf __unused, size_t len __unused) 2088bc9c9e2SClément Léger { 2098bc9c9e2SClément Léger return TEE_ERROR_NOT_SUPPORTED; 2108bc9c9e2SClément Léger } 2118bc9c9e2SClément Léger 2128bc9c9e2SClément Léger static inline TEE_Result i2c_smbus_raw(struct i2c_dev *i2c_dev __unused, 2138bc9c9e2SClément Léger enum i2c_smbus_dir dir __unused, 2148bc9c9e2SClément Léger enum i2c_smbus_protocol proto __unused, 2158bc9c9e2SClément Léger uint8_t cmd_code __unused, 2168bc9c9e2SClément Léger uint8_t *buf __unused, 2178bc9c9e2SClément Léger size_t len __unused) 2188bc9c9e2SClément Léger { 2198bc9c9e2SClément Léger return TEE_ERROR_NOT_SUPPORTED; 2208bc9c9e2SClément Léger } 2218bc9c9e2SClément Léger 2228bc9c9e2SClément Léger static inline TEE_Result i2c_dt_get_dev(const void *fdt __unused, 2238bc9c9e2SClément Léger int nodeoffset __unused, 2248bc9c9e2SClément Léger struct i2c_dev **i2c_dev) 2258bc9c9e2SClément Léger { 2268bc9c9e2SClément Léger return TEE_ERROR_NOT_SUPPORTED; 2278bc9c9e2SClément Léger } 2288bc9c9e2SClément Léger #endif 2298bc9c9e2SClément Léger 2308bc9c9e2SClément Léger /** 2318bc9c9e2SClément Léger * i2c_dt_get_func - Typedef of function to get I2C bus device from 2328bc9c9e2SClément Léger * devicetree properties 2338bc9c9e2SClément Léger * 2348fd620f7SEtienne Carriere * @args: Pointer to devicetree description of the I2C bus device to parse 2358bc9c9e2SClément Léger * @data: Pointer to data given at i2c_dt_register_provider() call 236*b357d34fSEtienne Carriere * @out_device: Output pointer to I2C device upon success 2378bc9c9e2SClément Léger */ 238*b357d34fSEtienne Carriere typedef TEE_Result (*i2c_dt_get_func)(struct dt_pargs *args, void *data, 239*b357d34fSEtienne Carriere struct i2c_dev **out_device); 2408bc9c9e2SClément Léger 2418bc9c9e2SClément Léger /** 2428bc9c9e2SClément Léger * i2c_dt_register_provider - Register a I2C controller provider and add all the 2438bc9c9e2SClément Léger * child nodes of this controller in the DT probe list. 2448bc9c9e2SClément Léger * 2458bc9c9e2SClément Léger * @fdt: Device tree to work on 2468bc9c9e2SClément Léger * @nodeoffset: Node offset of the I2C controller 2478bc9c9e2SClément Léger * @get_dt_i2c: Callback to match the I2C controller with a struct i2c 2488bc9c9e2SClément Léger * @data: Data which will be passed to the get_dt_i2c callback 2498bc9c9e2SClément Léger * Returns TEE_Result value 2508bc9c9e2SClément Léger */ 251*b357d34fSEtienne Carriere static inline TEE_Result i2c_register_provider(const void *fdt, int nodeoffset, 252*b357d34fSEtienne Carriere i2c_dt_get_func get_dt_i2c, 253*b357d34fSEtienne Carriere void *data) 2548bc9c9e2SClément Léger { 2558bc9c9e2SClément Léger int subnode = -1; 2568bc9c9e2SClément Léger TEE_Result res = TEE_ERROR_GENERIC; 2578bc9c9e2SClément Léger 2588bc9c9e2SClément Léger res = dt_driver_register_provider(fdt, nodeoffset, 2598bc9c9e2SClément Léger (get_of_device_func)get_dt_i2c, 2608bc9c9e2SClément Léger data, DT_DRIVER_I2C); 2618bc9c9e2SClément Léger if (res) 2628bc9c9e2SClément Léger return res; 2638bc9c9e2SClément Léger 2648bc9c9e2SClément Léger fdt_for_each_subnode(subnode, fdt, nodeoffset) 2658bc9c9e2SClément Léger dt_driver_maybe_add_probe_node(fdt, subnode); 2668bc9c9e2SClément Léger 2678bc9c9e2SClément Léger return TEE_SUCCESS; 2688bc9c9e2SClément Léger } 2698bc9c9e2SClément Léger 2708bc9c9e2SClément Léger /** 2718bc9c9e2SClément Léger * i2c_smbus_read_byte_data() - Execute a read byte SMBus protocol operation 2728bc9c9e2SClément Léger * 2738bc9c9e2SClément Léger * @i2c_dev: I2C device used for SMBus operation 2748bc9c9e2SClément Léger * @cmd_code: Command code to read 2758bc9c9e2SClément Léger * @byte: Returned byte value read from device 2768bc9c9e2SClément Léger * 2778bc9c9e2SClément Léger * Return a TEE_Result compliant value 2788bc9c9e2SClément Léger */ 2798bc9c9e2SClément Léger static inline TEE_Result i2c_smbus_read_byte_data(struct i2c_dev *i2c_dev, 2808bc9c9e2SClément Léger uint8_t cmd_code, 2818bc9c9e2SClément Léger uint8_t *byte) 2828bc9c9e2SClément Léger { 2838bc9c9e2SClément Léger return i2c_smbus_raw(i2c_dev, I2C_SMBUS_READ, I2C_SMBUS_PROTO_BYTE, 2848bc9c9e2SClément Léger cmd_code, byte, 1); 2858bc9c9e2SClément Léger } 2868bc9c9e2SClément Léger 2878bc9c9e2SClément Léger /** 2888bc9c9e2SClément Léger * i2c_smbus_write_byte_data() - Execute a write byte SMBus protocol operation 2898bc9c9e2SClément Léger * 2908bc9c9e2SClément Léger * @i2c_dev: I2C device used for SMBus operation 2918bc9c9e2SClément Léger * @cmd_code: Command code for write operation 2928bc9c9e2SClément Léger * @byte: Byte to be written to the device 2938bc9c9e2SClément Léger * 2948bc9c9e2SClément Léger * Return a TEE_Result compliant value 2958bc9c9e2SClément Léger */ 2968bc9c9e2SClément Léger static inline TEE_Result i2c_smbus_write_byte_data(struct i2c_dev *i2c_dev, 2978bc9c9e2SClément Léger uint8_t cmd_code, 2988bc9c9e2SClément Léger uint8_t byte) 2998bc9c9e2SClément Léger { 3008bc9c9e2SClément Léger return i2c_smbus_raw(i2c_dev, I2C_SMBUS_WRITE, I2C_SMBUS_PROTO_BYTE, 3018bc9c9e2SClément Léger cmd_code, &byte, 1); 3028bc9c9e2SClément Léger } 3038bc9c9e2SClément Léger 3048bc9c9e2SClément Léger /** 3058bc9c9e2SClément Léger * i2c_bus_read_block_raw() - Execute a non-standard SMBus raw block read. 3068bc9c9e2SClément Léger * This does not insert the "count" of byte to be written unlike the SMBus block 3078bc9c9e2SClément Léger * read operation. 3088bc9c9e2SClément Léger * 3098bc9c9e2SClément Léger * @i2c_dev: I2C device used for SMBus operation 3108bc9c9e2SClément Léger * @cmd_code: Command code for read operation 3118bc9c9e2SClément Léger * @buf: Buffer of data read from device 3128bc9c9e2SClément Léger * @len: Length of data to be read from the device 3138bc9c9e2SClément Léger * 3148bc9c9e2SClément Léger * Return a TEE_Result compliant value 3158bc9c9e2SClément Léger */ 3168bc9c9e2SClément Léger static inline TEE_Result i2c_bus_read_block_raw(struct i2c_dev *i2c_dev, 3178bc9c9e2SClément Léger uint8_t cmd_code, uint8_t *buf, 3188bc9c9e2SClément Léger size_t len) 3198bc9c9e2SClément Léger { 3208bc9c9e2SClément Léger return i2c_smbus_raw(i2c_dev, I2C_SMBUS_READ, I2C_SMBUS_PROTO_BLOCK_RAW, 3218bc9c9e2SClément Léger cmd_code, buf, len); 3228bc9c9e2SClément Léger } 3238bc9c9e2SClément Léger 3248bc9c9e2SClément Léger /** 3258bc9c9e2SClément Léger * i2c_bus_write_block_raw() - Execute a non-standard SMBus raw block write. 3268bc9c9e2SClément Léger * This does not insert the "count" of byte to be written unlike the SMBus block 3278bc9c9e2SClément Léger * write operation. 3288bc9c9e2SClément Léger * 3298bc9c9e2SClément Léger * @i2c_dev: I2C device used for SMBus operation 3308bc9c9e2SClément Léger * @cmd_code: Command code for write operation 3318bc9c9e2SClément Léger * @buf: Buffer of data to be written to the device 3328bc9c9e2SClément Léger * @len: Length of data to be written to the device 3338bc9c9e2SClément Léger * 3348bc9c9e2SClément Léger * Return a TEE_Result compliant value 3358bc9c9e2SClément Léger */ 3368bc9c9e2SClément Léger static inline TEE_Result i2c_bus_write_block_raw(struct i2c_dev *i2c_dev, 3378bc9c9e2SClément Léger uint8_t cmd_code, 3388bc9c9e2SClément Léger uint8_t *buf, size_t len) 3398bc9c9e2SClément Léger { 3408bc9c9e2SClément Léger return i2c_smbus_raw(i2c_dev, I2C_SMBUS_WRITE, 3418bc9c9e2SClément Léger I2C_SMBUS_PROTO_BLOCK_RAW, cmd_code, buf, len); 3428bc9c9e2SClément Léger } 3438bc9c9e2SClément Léger 3448bc9c9e2SClément Léger #endif 345