ifx_i2c.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433
  1. /**
  2. * MIT License
  3. *
  4. * Copyright (c) 2018 Infineon Technologies AG
  5. *
  6. * Permission is hereby granted, free of charge, to any person obtaining a copy
  7. * of this software and associated documentation files (the "Software"), to deal
  8. * in the Software without restriction, including without limitation the rights
  9. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10. * copies of the Software, and to permit persons to whom the Software is
  11. * furnished to do so, subject to the following conditions:
  12. *
  13. * The above copyright notice and this permission notice shall be included in all
  14. * copies or substantial portions of the Software.
  15. *
  16. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  19. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  22. * SOFTWARE
  23. *
  24. *
  25. * \file ifx_i2c.c
  26. *
  27. * \brief This file implements the wrapper API Layer for IFX I2C protocol v1.65.
  28. *
  29. * \addtogroup grIFXI2C
  30. * @{
  31. */
  32. /***********************************************************************************************************************
  33. * HEADER FILES
  34. **********************************************************************************************************************/
  35. #include "optiga/ifx_i2c/ifx_i2c.h"
  36. #include "optiga/ifx_i2c/ifx_i2c_transport_layer.h"
  37. #include "optiga/pal/pal_os_event.h"
  38. /// @cond hidden
  39. /***********************************************************************************************************************
  40. * MACROS
  41. **********************************************************************************************************************/
  42. // IFX I2C states
  43. #define IFX_I2C_STATE_UNINIT (0x01)
  44. #define IFX_I2C_STATE_IDLE (0x02)
  45. #define IFX_I2C_STATUS_BUSY (0x03)
  46. #define IFX_I2C_STATUS_NOT_BUSY (0x04)
  47. /// IFX I2C Reset states
  48. #define IFX_I2C_STATE_RESET_PIN_LOW (0xB1)
  49. #define IFX_I2C_STATE_RESET_PIN_HIGH (0xB2)
  50. #define IFX_I2C_STATE_RESET_INIT (0xB3)
  51. /***********************************************************************************************************************
  52. * ENUMS
  53. **********************************************************************************************************************/
  54. /***********************************************************************************************************************
  55. * DATA STRUCTURES
  56. ***********************************************************************************************************************/
  57. /***********************************************************************************************************************
  58. * GLOBAL
  59. ***********************************************************************************************************************/
  60. /***********************************************************************************************************************
  61. * LOCAL ROUTINES
  62. ***********************************************************************************************************************/
  63. /// Transport Layer event handler
  64. void ifx_i2c_tl_event_handler(ifx_i2c_context_t* p_ctx,host_lib_status_t event, const uint8_t* p_data, uint16_t data_len);
  65. /// Performs initialization
  66. static host_lib_status_t ifx_i2c_init(ifx_i2c_context_t* ifx_i2c_context);
  67. //lint --e{526} suppress "This API is defined in ifx_i2c_physical_layer. Since it is a low level API,
  68. //to avoid exposing, header file is not included "
  69. extern host_lib_status_t ifx_i2c_pl_write_slave_address(ifx_i2c_context_t *p_ctx, uint8_t slave_address, uint8_t storage_type);
  70. /// @endcond
  71. /***********************************************************************************************************************
  72. * API PROTOTYPES
  73. **********************************************************************************************************************/
  74. /**
  75. * Initializes the IFX I2C protocol stack for the given context.
  76. * <br>
  77. * <br>
  78. * \image html ifx_i2c_open.png "ifx_i2c_open()" width=20cm
  79. *
  80. *<b>Pre Conditions:</b>
  81. * - None<br>
  82. *
  83. *<b>API Details:</b>
  84. * - Performs a reset sequence.<br>
  85. * - Initializes the I2C slave device.<br>
  86. * - Initializes the ifx i2c protocol stack and registers the event callbacks.
  87. * - Negotiates the frame size and bit rate with the I2C slave.<br>
  88. *<br>
  89. *
  90. *<b>User Input:</b><br>
  91. * - The input #ifx_i2c_context_t p_ctx must not be NULL.
  92. * - The following parameters in #ifx_i2c_context_t must be initialized with appropriate values <br>
  93. * - <b>slave address</b> : Address of I2C slave
  94. * - <b>frame_size</b> : Frame size in bytes.Minimum supported value is 16 bytes.<br>
  95. * - It is recommended not to use a value greater than the slave's frame size.
  96. * - The user specified frame size is written to I2C slave's frame size register.
  97. * The frame size register is read back from I2C slave.
  98. * This frame value is used by the ifx-i2c protocol even if it is not equal to the user specified value.
  99. *
  100. * - <b>frequency</b> : Frequency/speed of I2C master in KHz.
  101. * - This must be lowest of the maximum frequency supported by the devices (master/slave) connected on the bus.
  102. * - Initial negotiation starts with a frequency of 100KHz.
  103. * - If the user specified frequency is more than 400 KHz, the I2C slave is configured to operate in "Fm+" mode,
  104. * otherwise the I2C slave is configured for "SM & Fm" mode. <br>
  105. * - If the user specified frequency frequency negotiation fails, the I2C master frequency remains at 100KHz<br>
  106. *
  107. * - <b>upper_layer_event_handler</b> : Upper layer event handler.This is invoked when #ifx_i2c_open() is asynchronously completed.
  108. * - <b>upper_layer_ctx</b> : Context of upper layer.
  109. * - <b>p_slave_vdd_pin</b> : GPIO pin for VDD. If not set, cold reset is not done.
  110. * - <b>p_slave_reset_pin</b> : GPIO pin for Reset. If not set, warm reset is not done.
  111. *
  112. *<b>Notes:</b>
  113. * - The values of registers MAX_SCL_FREQU and DATA_REG_LEN, read from slave are not validated.
  114. * - At present, only single instance of #ifx_i2c_context_t is supported.
  115. *
  116. *<br>
  117. *
  118. * \param[in,out] p_ctx Pointer to #ifx_i2c_context_t
  119. *
  120. * \retval #IFX_I2C_STACK_SUCCESS
  121. * \retval #IFX_I2C_STACK_ERROR
  122. */
  123. host_lib_status_t ifx_i2c_open(ifx_i2c_context_t *p_ctx)
  124. {
  125. host_lib_status_t api_status = (int32_t)IFX_I2C_STACK_ERROR;
  126. //If api status is not busy, proceed
  127. if ((IFX_I2C_STATUS_BUSY != p_ctx->status))
  128. {
  129. p_ctx->p_pal_i2c_ctx->upper_layer_ctx = p_ctx;
  130. #ifndef OPTIGA_USE_SOFT_RESET
  131. p_ctx->reset_type = (uint8_t)IFX_I2C_COLD_RESET;
  132. #else
  133. p_ctx->reset_type = (uint8_t)IFX_I2C_SOFT_RESET;
  134. #endif
  135. p_ctx->reset_state = IFX_I2C_STATE_RESET_PIN_LOW;
  136. p_ctx->do_pal_init = TRUE;
  137. p_ctx->state = IFX_I2C_STATE_UNINIT;
  138. api_status = ifx_i2c_init(p_ctx);
  139. if(IFX_I2C_STACK_SUCCESS == api_status)
  140. {
  141. p_ctx->status = IFX_I2C_STATUS_BUSY;
  142. }
  143. }
  144. return api_status;
  145. }
  146. /**
  147. * Resets the I2C slave and initializes the IFX I2C protocol stack for the given context.
  148. * <br>
  149. * <br>
  150. * \image html ifx_i2c_reset.png "ifx_i2c_reset()" width=20cm
  151. *
  152. *<b>Pre Conditions:</b>
  153. * - IFX I2C protocol stack must be initialized.<br>
  154. *
  155. *<b>API Details:</b>
  156. * - Resets the I2C slave.<br>
  157. * - Initializes the ifx i2c protocol stack.<br>
  158. * - Re-Initializes and negotiates the frame size and bit rate with the I2C slave.
  159. * The values remain same as that in previous #ifx_i2c_open().<br>
  160. *<br>
  161. *
  162. *<b>User Input:</b><br>
  163. * - The input #ifx_i2c_context_t p_ctx must not be NULL.
  164. *
  165. *<b>Notes:</b>
  166. * For COLD and WARM reset type: If the gpio(vdd and/or reset) pins are not configured,
  167. * the API continues without any failure return status<br>
  168. *
  169. * \param[in,out] p_ctx Pointer to #ifx_i2c_context_t
  170. * \param[in,out] reset_type type of reset
  171. *
  172. * \retval #IFX_I2C_STACK_SUCCESS
  173. * \retval #IFX_I2C_STACK_ERROR
  174. */
  175. host_lib_status_t ifx_i2c_reset(ifx_i2c_context_t *p_ctx, ifx_i2c_reset_type_t reset_type)
  176. {
  177. host_lib_status_t api_status = (int32_t)IFX_I2C_STACK_ERROR;
  178. // Proceed, if not busy and in idle state
  179. if ((IFX_I2C_STATE_IDLE == p_ctx->state) && (IFX_I2C_STATUS_BUSY != p_ctx->status))
  180. {
  181. p_ctx->reset_type = (uint8_t)reset_type;
  182. p_ctx->reset_state = IFX_I2C_STATE_RESET_PIN_LOW;
  183. p_ctx->do_pal_init = FALSE;
  184. api_status = ifx_i2c_init(p_ctx);
  185. if(IFX_I2C_STACK_SUCCESS == api_status)
  186. {
  187. p_ctx->status = IFX_I2C_STATUS_BUSY;
  188. }
  189. }
  190. return api_status;
  191. }
  192. /**
  193. * Sends a command and receives a response for the command.<br>
  194. * <br>
  195. * \image html ifx_i2c_transceive.png "ifx_i2c_transceive()" width=20cm
  196. *
  197. *
  198. *<b>Pre Conditions:</b>
  199. * - IFX I2C protocol stack must be initialized.<br>
  200. *
  201. *<b>API Details:</b>
  202. * - Transmit data(Command) to I2C slave.<br>
  203. * - Receive data(Response) from I2C slave.<br>
  204. *<br>
  205. *
  206. *<b>User Input:</b><br>
  207. * - The input #ifx_i2c_context_t p_ctx must not be NULL.
  208. * - The following parameters in #ifx_i2c_context_t must be initialized with appropriate values <br>
  209. * - <b>upper_layer_event_handler</b> : Upper layer event handler, if it is different from that in #ifx_i2c_open().
  210. * This is invoked when #ifx_i2c_transceive is asynchronously completed.
  211. * - <b>upper_layer_ctx</b> : Context of upper layer, if it is different from that in #ifx_i2c_open.
  212. *
  213. *<b>Notes:</b>
  214. * - The actual number of bytes received is stored in p_rx_buffer_len. In case of error,p_rx_buffer_len is set to 0.<br>
  215. * - If the size of p_rx_buffer is zero or insufficient to copy the response bytes then
  216. * #IFX_I2C_STACK_MEM_ERROR error is returned.
  217. *
  218. * \param[in,out] p_ctx Pointer to #ifx_i2c_context_t
  219. * \param[in] p_data Pointer to the write data buffer
  220. * \param[in] p_data_length Pointer to the length of the write data buffer
  221. * \param[in,out] p_rx_buffer Pointer to the receive data buffer
  222. * \param[in,out] p_rx_buffer_len Pointer to the length of the receive data buffer
  223. *
  224. * \retval #IFX_I2C_STACK_SUCCESS
  225. * \retval #IFX_I2C_STACK_ERROR
  226. * \retval #IFX_I2C_STACK_MEM_ERROR
  227. */
  228. host_lib_status_t ifx_i2c_transceive(ifx_i2c_context_t *p_ctx,const uint8_t* p_data, const uint16_t* p_data_length,
  229. uint8_t* p_rx_buffer, uint16_t* p_rx_buffer_len)
  230. {
  231. host_lib_status_t api_status = (int32_t)IFX_I2C_STACK_ERROR;
  232. // Proceed, if not busy and in idle state
  233. if ((IFX_I2C_STATE_IDLE == p_ctx->state) && (IFX_I2C_STATUS_BUSY != p_ctx->status))
  234. {
  235. p_ctx->p_upper_layer_rx_buffer = p_rx_buffer;
  236. p_ctx->p_upper_layer_rx_buffer_len = p_rx_buffer_len;
  237. api_status = ifx_i2c_tl_transceive(p_ctx,(uint8_t*)p_data, (*p_data_length),
  238. (uint8_t*)p_rx_buffer , p_rx_buffer_len);
  239. if (IFX_I2C_STACK_SUCCESS == api_status)
  240. {
  241. p_ctx->status = IFX_I2C_STATUS_BUSY;
  242. }
  243. }
  244. return api_status;
  245. }
  246. /**
  247. * Closes the IFX I2C protocol stack for a given context.
  248. * <br>
  249. * <br>
  250. * \image html ifx_i2c_close.png "ifx_i2c_close()" width=20cm
  251. *
  252. *<b>Pre Conditions:</b>
  253. * - None<br>
  254. *
  255. *<b>API Details:</b>
  256. * - De-Initializes the I2C slave device.<br>
  257. * - Power downs the I2C slave.<br>
  258. *<br>
  259. *
  260. *<b>User Input:</b><br>
  261. * - The input #ifx_i2c_context_t p_ctx must not be NULL.
  262. *
  263. *<b>Notes:</b>
  264. *
  265. * \param[in,out] p_ctx Pointer to #ifx_i2c_context_t
  266. *
  267. * \retval #IFX_I2C_STACK_SUCCESS
  268. */
  269. host_lib_status_t ifx_i2c_close(ifx_i2c_context_t *p_ctx)
  270. {
  271. host_lib_status_t api_status = (int32_t)IFX_I2C_STACK_ERROR;
  272. // Proceed, if not busy and in idle state
  273. if (IFX_I2C_STATUS_BUSY != p_ctx->status)
  274. {
  275. api_status = IFX_I2C_STACK_SUCCESS;
  276. //lint --e{534} suppress "Return value is not required to be checked"
  277. // Close I2C master
  278. pal_i2c_deinit(p_ctx->p_pal_i2c_ctx);
  279. // Also power off the device
  280. pal_gpio_set_low(p_ctx->p_slave_vdd_pin);
  281. pal_gpio_set_low(p_ctx->p_slave_reset_pin);
  282. ifx_i2c_tl_event_handler(p_ctx,IFX_I2C_STACK_SUCCESS,NULL,0);
  283. p_ctx->state = IFX_I2C_STATE_UNINIT;
  284. p_ctx->status = IFX_I2C_STATUS_NOT_BUSY;
  285. }
  286. return api_status;
  287. }
  288. /**
  289. * Writes new I2C slave Address to the target device.<br>
  290. *
  291. *<b>Pre Conditions:</b>
  292. * - IFX I2C protocol stack must be initialized.<br>
  293. *
  294. *<b>API Details:</b>
  295. * - This API is implemented in synchronous mode.
  296. * - If the write fails due to the following reasons, this API repeats the write for #PL_POLLING_MAX_CNT times
  297. * with a fixed interval of #PL_POLLING_INVERVAL_US microseconds and exits with respective return status.
  298. * - I2C bus is in busy state, returns #IFX_I2C_STACK_BUSY
  299. * - No-acknowledge(NACK) received from slave, returns #IFX_I2C_STACK_ERROR
  300. * - I2C errors, returns #IFX_I2C_STACK_ERROR
  301. * - Only bits [6:0] from parameter "slave_address" are considered as slave address. Hence the bit 7 is ignored.
  302. * - Slave address validation is not done in the implementation. Provide a valid slave address as input.
  303. *
  304. *<b>Notes:</b>
  305. * - If persistent mode is selected, the ifx i2c context slave address will be over-written with the new slave address.
  306. * Even after ifx i2c open/reset, all future executions will use the new slave address.<br>
  307. * - If volatile mode is selected, the pal_i2c_context slave address will be over-written with the new slave address.
  308. * This persists only till the next ifx_i2c open/reset is called.
  309. *
  310. * \param[in,out] p_ctx Pointer to #ifx_i2c_context_t
  311. * \param[in] slave_address Holds new slave address[7 Bit] to be set.
  312. * \param[in] persistent 0 - To set the Slave address until next reset.<br>
  313. * Non-zero - To set the slave address to persistent memory.
  314. *
  315. * \retval #IFX_I2C_STACK_SUCCESS
  316. * \retval #IFX_I2C_STACK_ERROR
  317. */
  318. host_lib_status_t ifx_i2c_set_slave_address(ifx_i2c_context_t *p_ctx, uint8_t slave_address, uint8_t persistent)
  319. {
  320. host_lib_status_t api_status = (int32_t)IFX_I2C_STACK_ERROR;
  321. if ((IFX_I2C_STATE_IDLE == p_ctx->state))
  322. {
  323. p_ctx->p_pal_i2c_ctx->upper_layer_ctx = p_ctx;
  324. api_status = ifx_i2c_pl_write_slave_address(p_ctx, slave_address, persistent);
  325. }
  326. return api_status;
  327. }
  328. /// @cond hidden
  329. //lint --e{715} suppress "This is ignored as ifx_i2c_event_handler_t handler function prototype requires this argument"
  330. void ifx_i2c_tl_event_handler(ifx_i2c_context_t* p_ctx,host_lib_status_t event, const uint8_t* p_data, uint16_t data_len)
  331. {
  332. // If there is no upper layer handler, don't do anything and return
  333. if (NULL != p_ctx->upper_layer_event_handler)
  334. {
  335. p_ctx->upper_layer_event_handler(p_ctx->p_upper_layer_ctx,event);
  336. }
  337. p_ctx->status = IFX_I2C_STATUS_NOT_BUSY;
  338. switch(p_ctx->state)
  339. {
  340. case IFX_I2C_STATE_UNINIT:
  341. if (IFX_I2C_STACK_SUCCESS == event)
  342. {
  343. p_ctx->state = IFX_I2C_STATE_IDLE;
  344. }
  345. break;
  346. default:
  347. break;
  348. }
  349. }
  350. static host_lib_status_t ifx_i2c_init(ifx_i2c_context_t* p_ifx_i2c_context)
  351. {
  352. host_lib_status_t api_status = IFX_I2C_STACK_ERROR;
  353. if ((p_ifx_i2c_context->reset_type == (uint8_t)IFX_I2C_WARM_RESET)||
  354. (p_ifx_i2c_context->reset_type == (uint8_t)IFX_I2C_COLD_RESET))
  355. {
  356. switch(p_ifx_i2c_context->reset_state)
  357. {
  358. case IFX_I2C_STATE_RESET_PIN_LOW:
  359. // Setting the Vdd & Reset pin to low
  360. if (p_ifx_i2c_context->reset_type == (uint8_t)IFX_I2C_COLD_RESET)
  361. {
  362. pal_gpio_set_low(p_ifx_i2c_context->p_slave_vdd_pin);
  363. }
  364. pal_gpio_set_low(p_ifx_i2c_context->p_slave_reset_pin);
  365. p_ifx_i2c_context->reset_state = IFX_I2C_STATE_RESET_PIN_HIGH;
  366. pal_os_event_register_callback_oneshot((register_callback)ifx_i2c_init,
  367. (void *)p_ifx_i2c_context, RESET_LOW_TIME_MSEC);
  368. api_status = IFX_I2C_STACK_SUCCESS;
  369. break;
  370. case IFX_I2C_STATE_RESET_PIN_HIGH:
  371. // Setting the Vdd & Reset pin to high
  372. if (p_ifx_i2c_context->reset_type == (uint8_t)IFX_I2C_COLD_RESET)
  373. {
  374. pal_gpio_set_high(p_ifx_i2c_context->p_slave_vdd_pin);
  375. }
  376. pal_gpio_set_high(p_ifx_i2c_context->p_slave_reset_pin);
  377. p_ifx_i2c_context->reset_state = IFX_I2C_STATE_RESET_INIT;
  378. pal_os_event_register_callback_oneshot((register_callback)ifx_i2c_init,
  379. (void *)p_ifx_i2c_context, STARTUP_TIME_MSEC);
  380. api_status = IFX_I2C_STACK_SUCCESS;
  381. break;
  382. case IFX_I2C_STATE_RESET_INIT:
  383. //Frequency and frame size negotiation
  384. api_status = ifx_i2c_tl_init(p_ifx_i2c_context,ifx_i2c_tl_event_handler);
  385. break;
  386. default:
  387. break;
  388. }
  389. }
  390. //soft reset
  391. else
  392. {
  393. p_ifx_i2c_context->pl.request_soft_reset = (uint8_t)TRUE; //Soft reset
  394. api_status = ifx_i2c_tl_init(p_ifx_i2c_context,ifx_i2c_tl_event_handler);
  395. }
  396. return api_status;
  397. }
  398. /// @endcond
  399. /**
  400. * @}
  401. */