1 /*******************************************************************************
2 * File Name: cyhal_i2c.c
3 *
4 * Description:
5 * Provides a high level interface for interacting with the Infineon I2C. This is
6 * a wrapper around the lower level PDL API.
7 *
8 ********************************************************************************
9 * \copyright
10 * Copyright 2018-2022 Cypress Semiconductor Corporation (an Infineon company) or
11 * an affiliate of Cypress Semiconductor Corporation
12 *
13 * SPDX-License-Identifier: Apache-2.0
14 *
15 * Licensed under the Apache License, Version 2.0 (the "License");
16 * you may not use this file except in compliance with the License.
17 * You may obtain a copy of the License at
18 *
19 *     http://www.apache.org/licenses/LICENSE-2.0
20 *
21 * Unless required by applicable law or agreed to in writing, software
22 * distributed under the License is distributed on an "AS IS" BASIS,
23 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
24 * See the License for the specific language governing permissions and
25 * limitations under the License.
26 *******************************************************************************/
27 
28 #include <stdlib.h>
29 #include <string.h>
30 #include "cyhal_i2c.h"
31 #include "cyhal_scb_common.h"
32 #include "cyhal_gpio.h"
33 #include "cyhal_hwmgr.h"
34 #include "cyhal_system.h"
35 #include "cyhal_syspm.h"
36 #include "cyhal_utils.h"
37 #include "cyhal_irq_impl.h"
38 #include "cyhal_clock.h"
39 
40 #if (CYHAL_DRIVER_AVAILABLE_I2C)
41 
42 #if defined(__cplusplus)
43 extern "C"
44 {
45 #endif
46 
47 #define _CYHAL_I2C_PENDING_NONE              0
48 #define _CYHAL_I2C_PENDING_RX                1
49 #define _CYHAL_I2C_PENDING_TX                2
50 #define _CYHAL_I2C_PENDING_TX_RX             3
51 
52 #define _CYHAL_I2C_MASTER_DEFAULT_FREQ       100000
53 
54 
55 static const _cyhal_buffer_info_t _cyhal_i2c_buff_info_default = {
56     .addr = {NULL},
57     .size = 0,
58 };
59 
60 static const cy_stc_scb_i2c_config_t _cyhal_i2c_default_config = {
61         .i2cMode   = CY_SCB_I2C_MASTER,
62         .useRxFifo = false,
63         .useTxFifo = true,
64         .slaveAddress     = 0U,
65         .slaveAddressMask = 0U,
66         .acceptAddrInFifo = false,
67         .ackGeneralAddr   = false,
68         .enableWakeFromSleep = false,
69         .enableDigitalFilter = false,
70         .lowPhaseDutyCycle = 8U,
71         .highPhaseDutyCycle = 8U,
72 };
73 
74 
75 /* The PDL clears the IRQ status during Cy_SCB_I2C_Interrupt which prevents _cyhal_scb_get_irq_obj()
76  * from working properly in _cyhal_i2c_cb_wrapper on devices with muxed IRQs, because they can't tell
77  * at that point which system IRQ caused the CPU IRQ. So we need to save this value at the beginning of the
78  * IRQ handler when we are able to determine what it is */
79 static volatile cyhal_i2c_t* _cyhal_i2c_irq_obj = NULL;
80 
_cyhal_i2c_convert_interrupt_cause(uint32_t pdl_cause)81 static cyhal_i2c_event_t _cyhal_i2c_convert_interrupt_cause(uint32_t pdl_cause)
82 {
83     static const uint32_t status_map1[] =
84     {
85         (uint32_t)CYHAL_I2C_EVENT_NONE,                 // Default no event
86         (uint32_t)CYHAL_I2C_SLAVE_READ_EVENT,           // CY_SCB_I2C_SLAVE_READ_EVENT
87         (uint32_t)CYHAL_I2C_SLAVE_WRITE_EVENT,          // CY_SCB_I2C_SLAVE_WRITE_EVENT
88         (uint32_t)CYHAL_I2C_SLAVE_RD_IN_FIFO_EVENT,     // CY_SCB_I2C_SLAVE_RD_IN_FIFO_EVENT
89         (uint32_t)CYHAL_I2C_SLAVE_RD_BUF_EMPTY_EVENT,   // CY_SCB_I2C_SLAVE_RD_BUF_EMPTY_EVENT
90         (uint32_t)CYHAL_I2C_SLAVE_RD_CMPLT_EVENT,       // CY_SCB_I2C_SLAVE_RD_CMPLT_EVENT
91         (uint32_t)CYHAL_I2C_SLAVE_WR_CMPLT_EVENT,       // CY_SCB_I2C_SLAVE_WR_CMPLT_EVENT
92         (uint32_t)CYHAL_I2C_SLAVE_ERR_EVENT,            // CY_SCB_I2C_SLAVE_ERR_EVENT
93     };
94     uint32_t set1 = _cyhal_utils_convert_flags(status_map1, sizeof(status_map1) / sizeof(uint32_t), pdl_cause & 0xFF);
95 
96     static const uint32_t status_map2[] =
97     {
98         (uint32_t)CYHAL_I2C_EVENT_NONE,                 // Default no event
99         (uint32_t)CYHAL_I2C_MASTER_WR_IN_FIFO_EVENT,    // CY_SCB_I2C_MASTER_WR_IN_FIFO_EVENT
100         (uint32_t)CYHAL_I2C_MASTER_WR_CMPLT_EVENT,      // CY_SCB_I2C_MASTER_WR_CMPLT_EVENT
101         (uint32_t)CYHAL_I2C_MASTER_RD_CMPLT_EVENT,      // CY_SCB_I2C_MASTER_RD_CMPLT_EVENT
102         (uint32_t)CYHAL_I2C_MASTER_ERR_EVENT,           // CY_SCB_I2C_MASTER_ERR_EVENT
103     };
104     uint32_t set2 = _cyhal_utils_convert_flags(status_map2, sizeof(status_map2) / sizeof(uint32_t), pdl_cause >> 16);
105 
106     return (cyhal_i2c_event_t)(set1 | set2);
107 }
108 
_cyhal_i2c_convert_addr_interrupt_cause(uint32_t pdl_cause)109 static cyhal_i2c_addr_event_t _cyhal_i2c_convert_addr_interrupt_cause(uint32_t pdl_cause)
110 {
111     static const uint32_t status_map1[] =
112     {
113         (uint32_t)CYHAL_I2C_ADDR_EVENT_NONE,            // Default no event
114         (uint32_t)CYHAL_I2C_GENERAL_CALL_EVENT,         // CY_SCB_I2C_READ_EVENT
115         (uint32_t)CYHAL_I2C_ADDR_MATCH_EVENT,           // CY_SCB_I2C_ADDR_IN_FIFO_EVENT
116     };
117     uint32_t set1 = _cyhal_utils_convert_flags(status_map1, sizeof(status_map1) / sizeof(uint32_t), pdl_cause & 0xFF);
118 
119     return (cyhal_i2c_addr_event_t)(set1);
120 }
121 
122 #if defined (COMPONENT_CAT5)
_cyhal_i2c_irq_handler(_cyhal_system_irq_t irqn)123 static void _cyhal_i2c_irq_handler(_cyhal_system_irq_t irqn)
124 #else
125 static void _cyhal_i2c_irq_handler(void)
126 #endif
127 {
128     /* Save the old value and store it aftewards in case we get into a nested IRQ situation */
129     /* Safe to cast away volatile because we don't expect this pointer to be changed while we're in here, they
130      * just might change where the original pointer points */
131     cyhal_i2c_t* old_irq_obj = (cyhal_i2c_t*)_cyhal_i2c_irq_obj;
132 #if defined (COMPONENT_CAT5)
133     _cyhal_i2c_irq_obj = (cyhal_i2c_t*) _cyhal_scb_get_irq_obj(irqn);
134 #else
135     _cyhal_i2c_irq_obj = (cyhal_i2c_t*) _cyhal_scb_get_irq_obj();
136 #endif
137     cyhal_i2c_t* obj = (cyhal_i2c_t*)_cyhal_i2c_irq_obj;
138 
139     Cy_SCB_I2C_Interrupt(obj->base, &(obj->context));
140 
141     if (obj->pending)
142     {
143         /* This code is part of cyhal_i2c_master_transfer_async() API functionality */
144         /* cyhal_i2c_master_transfer_async() API uses this interrupt handler for RX transfer */
145         if (0 == (Cy_SCB_I2C_MasterGetStatus(obj->base,  &obj->context) & CY_SCB_I2C_MASTER_BUSY))
146         {
147             /* Check if TX is completed and run RX in case when TX and RX are enabled */
148             if (obj->pending == _CYHAL_I2C_PENDING_TX_RX)
149             {
150                 /* Start RX transfer */
151                 obj->pending = _CYHAL_I2C_PENDING_RX;
152                 Cy_SCB_I2C_MasterRead(obj->base, &obj->rx_config, &obj->context);
153             }
154             else
155             {
156                 /* Finish async TX or RX separate transfer */
157                 obj->pending = _CYHAL_I2C_PENDING_NONE;
158             }
159         }
160     }
161 
162     _cyhal_i2c_irq_obj = old_irq_obj;
163 }
164 
165 #if defined (COMPONENT_CAT5)
_cyhal_i2c0_irq_handler(void)166 static void _cyhal_i2c0_irq_handler(void)
167 {
168     _cyhal_i2c_irq_handler(scb_0_interrupt_IRQn);
169 }
170 
_cyhal_i2c1_irq_handler(void)171 static void _cyhal_i2c1_irq_handler(void)
172 {
173     _cyhal_i2c_irq_handler(scb_1_interrupt_IRQn);
174 }
175 
_cyhal_i2c2_irq_handler(void)176 static void _cyhal_i2c2_irq_handler(void)
177 {
178     _cyhal_i2c_irq_handler(scb_2_interrupt_IRQn);
179 }
180 
181 static CY_SCB_IRQ_THREAD_CB_t _cyhal_irq_cb[3] = {_cyhal_i2c0_irq_handler, _cyhal_i2c1_irq_handler, _cyhal_i2c2_irq_handler};
182 #endif
183 
_cyhal_i2c_cb_wrapper(uint32_t event)184 static void _cyhal_i2c_cb_wrapper(uint32_t event)
185 {
186     /* Safe to cast away volatile because we don't expect this pointer to be changed while we're in here, they
187      * just might change where the original pointer points */
188     cyhal_i2c_t *obj = (cyhal_i2c_t*)_cyhal_i2c_irq_obj;
189     cyhal_i2c_event_t anded_events = (cyhal_i2c_event_t)(obj->irq_cause & (uint32_t)_cyhal_i2c_convert_interrupt_cause(event));
190     if (anded_events)
191     {
192         /* Indicates read/write operations will be in a callback */
193         obj->op_in_callback = true;
194         cyhal_i2c_event_callback_t callback = (cyhal_i2c_event_callback_t) obj->callback_data.callback;
195         callback(obj->callback_data.callback_arg, anded_events);
196         obj->op_in_callback = false;
197     }
198 }
199 
_cyhal_i2c_cb_addr_wrapper(uint32_t event)200 static cy_en_scb_i2c_command_t _cyhal_i2c_cb_addr_wrapper(uint32_t event)
201 {
202     /* Safe to cast away volatile because we don't expect this pointer to be changed while we're in here, they
203      * just might change where the original pointer points */
204     cyhal_i2c_t *obj = (cyhal_i2c_t*)_cyhal_i2c_irq_obj;
205     cyhal_i2c_addr_event_t addr_events = (cyhal_i2c_addr_event_t)(obj->addr_irq_cause & (uint32_t)_cyhal_i2c_convert_addr_interrupt_cause(event));
206     uint8_t device_address = 0;
207     /* The default command is the ACK address. It can be overridden in an address callback */
208     cyhal_i2c_command_rsp_t cmd = CYHAL_I2C_CMD_ACK;
209     if (addr_events)
210     {
211         /* If ADDR_IN_FIFO_EVENT received, HAL need to read the device address using Cy_SCB_ReadRxFifo API as per I2C PDL documentation */
212         if (0L != (CYHAL_I2C_ADDR_MATCH_EVENT & addr_events))
213         {
214             /* Slave address stored in PDL is shifted left by 1, so to get correct slave address need to do LSR by 1 */
215             device_address = (Cy_SCB_ReadRxFifo(obj->base)) >> 1;
216         }
217         /* Indicates read/write operations will be in a callback */
218         obj->op_in_callback = true;
219         cyhal_i2c_address_callback_t callback = (cyhal_i2c_address_callback_t) obj->addr_callback_data.callback;
220         cmd = callback(obj->addr_callback_data.callback_arg, addr_events, device_address);
221         obj->op_in_callback = false;
222     }
223     return (cy_en_scb_i2c_command_t)cmd;
224 }
225 
_cyhal_i2c_pm_callback_instance(void * obj_ptr,cyhal_syspm_callback_state_t state,cy_en_syspm_callback_mode_t pdl_mode)226 static bool _cyhal_i2c_pm_callback_instance(void *obj_ptr, cyhal_syspm_callback_state_t state, cy_en_syspm_callback_mode_t pdl_mode)
227 {
228     cyhal_i2c_t *obj = (cyhal_i2c_t*)obj_ptr;
229     cy_stc_syspm_callback_params_t i2c_callback_params = {
230         .base = (void *) (obj->base),
231         .context = (void *) &(obj->context)
232     };
233     bool allow = true;
234 
235     if ((CYHAL_SYSPM_CB_CPU_DEEPSLEEP == state) || (CYHAL_SYSPM_CB_CPU_DEEPSLEEP_RAM == state))
236         allow = (CY_SYSPM_SUCCESS == Cy_SCB_I2C_DeepSleepCallback(&i2c_callback_params, pdl_mode));
237 #if defined(COMPONENT_CAT1A) || defined(COMPONENT_CAT1B) || defined(COMPONENT_CAT1C) || defined(COMPONENT_CAT1D)
238     else if (CYHAL_SYSPM_CB_SYSTEM_HIBERNATE == state)
239         allow = (CY_SYSPM_SUCCESS == Cy_SCB_I2C_HibernateCallback(&i2c_callback_params, pdl_mode));
240 #endif
241 
242     return allow;
243 }
244 
245 
_cyhal_i2c_init_resources(cyhal_i2c_t * obj,cyhal_gpio_t sda,cyhal_gpio_t scl,const cyhal_clock_t * clk)246 static cy_rslt_t _cyhal_i2c_init_resources(cyhal_i2c_t *obj, cyhal_gpio_t sda, cyhal_gpio_t scl, const cyhal_clock_t *clk)
247 {
248     /* Explicitly marked not allocated resources as invalid to prevent freeing them. */
249     obj->resource.type = CYHAL_RSC_INVALID;
250     obj->pin_scl = CYHAL_NC_PIN_VALUE;
251     obj->pin_sda = CYHAL_NC_PIN_VALUE;
252     obj->is_clock_owned = false;
253 
254     // pins_blocks will contain bit representation of blocks, that are connected to specified pin
255     // 1 block - 1 bit, so, for example, pin_blocks = 0x00000006 means that certain pin
256     // can belong to next non-reserved blocks SCB2 and SCB1
257     uint32_t pins_blocks = _CYHAL_SCB_AVAILABLE_BLOCKS_MASK;
258     if (NC != sda)
259     {
260         pins_blocks &= _CYHAL_SCB_CHECK_AFFILIATION(sda, cyhal_pin_map_scb_i2c_sda);
261     }
262     if (NC != scl)
263     {
264         pins_blocks &= _CYHAL_SCB_CHECK_AFFILIATION(scl, cyhal_pin_map_scb_i2c_scl);
265     }
266 
267     // One (or more) pin does not belong to any SCB instance or all corresponding SCB instances
268     // are reserved
269     if (0 == pins_blocks)
270     {
271         return CYHAL_I2C_RSLT_ERR_INVALID_PIN;
272     }
273 
274     uint8_t found_block_idx = 0;
275     while(((pins_blocks >> found_block_idx) & 0x1) == 0)
276     {
277         found_block_idx++;
278     }
279 
280     cyhal_resource_inst_t i2c_rsc = { CYHAL_RSC_SCB, found_block_idx, 0 };
281 
282     /* Reserve the I2C */
283     const cyhal_resource_pin_mapping_t *sda_map = _CYHAL_SCB_FIND_MAP_BLOCK(sda, cyhal_pin_map_scb_i2c_sda, &i2c_rsc);
284     const cyhal_resource_pin_mapping_t *scl_map = _CYHAL_SCB_FIND_MAP_BLOCK(scl, cyhal_pin_map_scb_i2c_scl, &i2c_rsc);
285     uint8_t scb_arr_index = 0;
286 
287     if ((NULL == sda_map) || (NULL == scl_map) || !_cyhal_utils_map_resources_equal(sda_map, scl_map))
288     {
289         return CYHAL_I2C_RSLT_ERR_INVALID_PIN;
290     }
291 
292 
293     cyhal_resource_inst_t rsc_to_reserve = { CYHAL_RSC_SCB, _cyhal_scb_get_block_index(found_block_idx), 0 };
294     cy_rslt_t result = cyhal_hwmgr_reserve(&rsc_to_reserve);
295 
296     if (result == CY_RSLT_SUCCESS)
297     {
298         scb_arr_index = _cyhal_scb_get_block_index(i2c_rsc.block_num);
299         obj->base = _CYHAL_SCB_BASE_ADDRESSES[scb_arr_index];
300         obj->resource = i2c_rsc;
301 
302         result = _cyhal_utils_reserve_and_connect(sda_map, (uint8_t)CYHAL_PIN_MAP_DRIVE_MODE_SCB_I2C_SDA);
303         if (result == CY_RSLT_SUCCESS)
304             obj->pin_sda = sda;
305     }
306 
307     if (result == CY_RSLT_SUCCESS)
308     {
309         result = _cyhal_utils_reserve_and_connect(scl_map, (uint8_t)CYHAL_PIN_MAP_DRIVE_MODE_SCB_I2C_SCL);
310         if (result == CY_RSLT_SUCCESS)
311             obj->pin_scl = scl;
312     }
313 
314     if (result == CY_RSLT_SUCCESS)
315     {
316         if (clk == NULL)
317         {
318             result = _cyhal_utils_allocate_clock(&(obj->clock), &(obj->resource), CYHAL_CLOCK_BLOCK_PERIPHERAL_16BIT, true);
319             obj->is_clock_owned = (result == CY_RSLT_SUCCESS);
320         }
321         else
322         {
323             obj->clock = *clk;
324         }
325     }
326 
327     if (result == CY_RSLT_SUCCESS)
328     {
329         uint32_t dataRate = _cyhal_i2c_set_peri_divider((void *)obj, true, _CYHAL_I2C_MASTER_DEFAULT_FREQ, false);
330         if (dataRate == 0)
331         {
332             /* Can not reach desired data rate */
333             result = CYHAL_I2C_RSLT_ERR_CAN_NOT_REACH_DR;
334         }
335     }
336 
337     return result;
338 }
339 
_cyhal_i2c_init_hw(cyhal_i2c_t * obj,const cy_stc_scb_i2c_config_t * pdl_cfg)340 static cy_rslt_t _cyhal_i2c_init_hw(cyhal_i2c_t *obj, const cy_stc_scb_i2c_config_t *pdl_cfg)
341 {
342     CY_ASSERT(NULL != obj->base);
343 
344     /* Initial value for async operations */
345     obj->pending = _CYHAL_I2C_PENDING_NONE;
346     /* Initial value for read/write operations in callback */
347     obj->op_in_callback = false;
348 
349     obj->rx_slave_buff = _cyhal_i2c_buff_info_default;
350     obj->tx_slave_buff = _cyhal_i2c_buff_info_default;
351 
352     /* Configure I2C to operate */
353     cy_rslt_t result = (cy_rslt_t)Cy_SCB_I2C_Init(obj->base, pdl_cfg, &(obj->context));
354     uint8_t scb_arr_index = _cyhal_scb_get_block_index(obj->resource.block_num);
355 
356     if (result == CY_RSLT_SUCCESS)
357     {
358         _cyhal_scb_update_instance_data(obj->resource.block_num, (void*)obj, &_cyhal_i2c_pm_callback_instance);
359         /* Enable I2C to operate */
360 #if defined(COMPONENT_CAT1A) || defined(COMPONENT_CAT1B) || defined(COMPONENT_CAT1C) || defined(COMPONENT_CAT1D)
361         Cy_SCB_I2C_Enable(obj->base);
362 #elif defined(COMPONENT_CAT2)
363         Cy_SCB_I2C_Enable(obj->base, &(obj->context));
364 #endif
365         obj->callback_data.callback = NULL;
366         obj->callback_data.callback_arg = NULL;
367         obj->addr_callback_data.callback = NULL;
368         obj->addr_callback_data.callback_arg = NULL;
369         obj->irq_cause = CYHAL_I2C_EVENT_NONE;
370         obj->addr_irq_cause = CYHAL_I2C_ADDR_EVENT_NONE;
371 
372         #if defined (COMPONENT_CAT5)
373             Cy_SCB_RegisterInterruptCallback(obj->base, _cyhal_irq_cb[_CYHAL_SCB_IRQ_N[scb_arr_index]]);
374             Cy_SCB_EnableInterrupt(obj->base);
375         #endif
376 
377         _cyhal_irq_register(_CYHAL_SCB_IRQ_N[scb_arr_index], CYHAL_ISR_PRIORITY_DEFAULT, (cy_israddress)_cyhal_i2c_irq_handler);
378         _cyhal_irq_enable(_CYHAL_SCB_IRQ_N[scb_arr_index]);
379     }
380 
381     return result;
382 }
383 
_cyhal_i2c_slave_status(cyhal_i2c_t * obj)384 __STATIC_INLINE uint32_t _cyhal_i2c_slave_status(cyhal_i2c_t *obj)
385 {
386     return Cy_SCB_I2C_SlaveGetStatus(obj->base, &obj->context);
387 }
388 
_cyhal_i2c_slave_clear_write_status(cyhal_i2c_t * obj)389 __STATIC_INLINE void _cyhal_i2c_slave_clear_write_status(cyhal_i2c_t *obj)
390 {
391     (void)Cy_SCB_I2C_SlaveClearWriteStatus(obj->base, &obj->context);
392 }
393 
_cyhal_i2c_slave_clear_read_status(cyhal_i2c_t * obj)394 __STATIC_INLINE void _cyhal_i2c_slave_clear_read_status(cyhal_i2c_t *obj)
395 {
396     (void)Cy_SCB_I2C_SlaveClearReadStatus(obj->base, &obj->context);
397 }
398 
399 /* Wait for I2C slave status for some time (timeout > 0) or no wait (timeout == 0).
400 * The function returns CYHAL_I2C_RSLT_WARN_TIMEOUT in case timeout reached, otherwise - CY_RSLT_SUCCESS
401 * NOTE: When the read/write operation was called in a I2C callback function timeout is ignored
402 */
_cyhal_i2c_slave_wait_for_status(cyhal_i2c_t * obj,uint32_t i2c_status,uint32_t timeout)403 static cy_rslt_t _cyhal_i2c_slave_wait_for_status(cyhal_i2c_t *obj, uint32_t i2c_status, uint32_t timeout)
404 {
405     cy_rslt_t result = CY_RSLT_SUCCESS;
406     uint32_t timeout_us = _CYHAL_UTILS_US_PER_MS;
407 
408     if (!(obj->op_in_callback) && timeout > 0)
409     {
410         while (0U == (_cyhal_i2c_slave_status(obj) & i2c_status) && timeout > 0)
411         {
412             if (timeout_us > 0)
413             {
414                 cyhal_system_delay_us(_CYHAL_UTILS_ONE_TIME_UNIT);
415                 --timeout_us;
416             }
417             else
418             {
419                 timeout_us = _CYHAL_UTILS_US_PER_MS;
420                 --timeout;
421             }
422         }
423         result = (timeout > 0) ? CY_RSLT_SUCCESS : CYHAL_I2C_RSLT_WARN_TIMEOUT;
424     }
425     return result;
426 }
427 
428 /* Start API implementing */
cyhal_i2c_init(cyhal_i2c_t * obj,cyhal_gpio_t sda,cyhal_gpio_t scl,const cyhal_clock_t * clk)429 cy_rslt_t cyhal_i2c_init(cyhal_i2c_t *obj, cyhal_gpio_t sda, cyhal_gpio_t scl, const cyhal_clock_t *clk)
430 {
431     CY_ASSERT(NULL != obj);
432     obj->dc_configured = false;
433     memset(obj, 0, sizeof(cyhal_i2c_t));
434 
435     cy_rslt_t result = _cyhal_i2c_init_resources(obj, sda, scl, clk);
436     if (CY_RSLT_SUCCESS == result)
437     {
438         result = _cyhal_i2c_init_hw(obj, &_cyhal_i2c_default_config);
439     }
440     if (CY_RSLT_SUCCESS != result)
441     {
442         cyhal_i2c_free(obj);
443     }
444     return result;
445 }
446 
cyhal_i2c_init_cfg(cyhal_i2c_t * obj,const cyhal_i2c_configurator_t * cfg)447 cy_rslt_t cyhal_i2c_init_cfg(cyhal_i2c_t *obj, const cyhal_i2c_configurator_t *cfg)
448 {
449     CY_ASSERT(NULL != obj);
450     CY_ASSERT(NULL != cfg);
451     CY_ASSERT(NULL != cfg->config);
452 
453     memset(obj, 0, sizeof(cyhal_i2c_t));
454 
455     obj->dc_configured = true;
456     obj->resource = *cfg->resource;
457     obj->clock = *cfg->clock;
458     obj->is_clock_owned = false;
459 
460     uint8_t scb_arr_index = _cyhal_scb_get_block_index(obj->resource.block_num);
461     obj->base = _CYHAL_SCB_BASE_ADDRESSES[scb_arr_index];
462 
463     return _cyhal_i2c_init_hw(obj, cfg->config);
464 }
465 
cyhal_i2c_free(cyhal_i2c_t * obj)466 void cyhal_i2c_free(cyhal_i2c_t *obj)
467 {
468     CY_ASSERT(NULL != obj);
469 
470     if (NULL != obj->base)
471     {
472         Cy_SCB_I2C_Disable(obj->base, &obj->context);
473         Cy_SCB_I2C_DeInit(obj->base);
474         obj->base = NULL;
475     }
476 
477     if (CYHAL_RSC_INVALID != obj->resource.type)
478     {
479         uint8_t scb_arr_index = _cyhal_scb_get_block_index(obj->resource.block_num);
480         _cyhal_scb_update_instance_data(obj->resource.block_num, NULL, NULL);
481         _cyhal_system_irq_t irqn = _CYHAL_SCB_IRQ_N[scb_arr_index];
482         _cyhal_irq_free(irqn);
483 
484         if (!obj->dc_configured)
485         {
486             cyhal_resource_inst_t rsc_to_free = { CYHAL_RSC_SCB, _cyhal_scb_get_block_index(obj->resource.block_num), obj->resource.channel_num };
487             cyhal_hwmgr_free(&(rsc_to_free));
488         }
489 
490         obj->resource.type = CYHAL_RSC_INVALID;
491     }
492 
493     if (!obj->dc_configured)
494     {
495         _cyhal_utils_release_if_used(&(obj->pin_sda));
496         _cyhal_utils_release_if_used(&(obj->pin_scl));
497 
498         if (obj->is_clock_owned)
499         {
500             cyhal_clock_free(&(obj->clock));
501         }
502     }
503 }
504 
cyhal_i2c_configure(cyhal_i2c_t * obj,const cyhal_i2c_cfg_t * cfg)505 cy_rslt_t cyhal_i2c_configure(cyhal_i2c_t *obj, const cyhal_i2c_cfg_t *cfg)
506 {
507     CY_ASSERT(NULL != obj);
508     CY_ASSERT(NULL != cfg);
509 
510     /* Prepare advanced configuration structure */
511     cyhal_i2c_adv_cfg_t adv_cfg = {
512         .basic_cfg = *cfg,
513         /* Fill advanced parameters by default values */
514         .address_mask = CYHAL_I2C_DEFAULT_ADDR_MASK,
515         .enable_address_callback = false,
516     };
517 
518     return cyhal_i2c_configure_adv(obj, &adv_cfg);
519 }
520 
cyhal_i2c_configure_adv(cyhal_i2c_t * obj,const cyhal_i2c_adv_cfg_t * cfg)521 cy_rslt_t cyhal_i2c_configure_adv(cyhal_i2c_t *obj, const cyhal_i2c_adv_cfg_t *cfg)
522 {
523     CY_ASSERT(NULL != obj);
524     CY_ASSERT(NULL != cfg);
525     CY_ASSERT(NULL != &cfg->basic_cfg);
526 
527     (void) Cy_SCB_I2C_Disable(obj->base, &obj->context);
528 
529     cy_stc_scb_i2c_config_t _config_structure = _cyhal_i2c_default_config;
530 
531     _config_structure.i2cMode = (cfg->basic_cfg.is_slave)
532         ? CY_SCB_I2C_SLAVE
533         : CY_SCB_I2C_MASTER;
534 
535     _config_structure.slaveAddress  = (uint8_t)cfg->basic_cfg.address;
536 
537     if (cfg->basic_cfg.is_slave)
538     {
539         _config_structure.acceptAddrInFifo = cfg->enable_address_callback;
540         _config_structure.ackGeneralAddr   = cfg->enable_address_callback;
541         _config_structure.slaveAddressMask = cfg->address_mask;
542     }
543 
544     cy_rslt_t result = (cy_rslt_t)Cy_SCB_I2C_Init(obj->base, &_config_structure, &(obj->context));
545     if (CY_RSLT_SUCCESS == result)
546     {
547         /* Set data rate */
548         uint32_t dataRate = _cyhal_i2c_set_peri_divider((void *)obj, true,
549                                 cfg->basic_cfg.frequencyhal_hz, cfg->basic_cfg.is_slave);
550         if (dataRate == 0)
551         {
552             /* Deinit SCB block */
553             Cy_SCB_I2C_DeInit(obj->base);
554             /* Can not reach desired data rate */
555             return CYHAL_I2C_RSLT_ERR_CAN_NOT_REACH_DR;
556         }
557 
558     #if defined(COMPONENT_CAT1A) || defined(COMPONENT_CAT1B) || defined(COMPONENT_CAT1C) || defined(COMPONENT_CAT1D)
559         (void) Cy_SCB_I2C_Enable(obj->base);
560     #elif defined(COMPONENT_CAT2)
561         (void) Cy_SCB_I2C_Enable(obj->base, &(obj->context));
562     #endif
563     }
564     return result;
565 }
566 
cyhal_i2c_master_write(cyhal_i2c_t * obj,uint16_t dev_addr,const uint8_t * data,uint16_t size,uint32_t timeout,bool send_stop)567 cy_rslt_t cyhal_i2c_master_write(cyhal_i2c_t *obj, uint16_t dev_addr, const uint8_t *data, uint16_t size, uint32_t timeout, bool send_stop)
568 {
569     if (_cyhal_scb_pm_transition_pending())
570         return CYHAL_SYSPM_RSLT_ERR_PM_PENDING;
571 
572     cy_en_scb_i2c_status_t status = (obj->context.state == CY_SCB_I2C_IDLE)
573         ? Cy_SCB_I2C_MasterSendStart(obj->base, dev_addr, CY_SCB_I2C_WRITE_XFER, timeout, &obj->context)
574         : Cy_SCB_I2C_MasterSendReStart(obj->base, dev_addr, CY_SCB_I2C_WRITE_XFER, timeout, &obj->context);
575 
576     if (status == CY_SCB_I2C_SUCCESS)
577     {
578         while (size > 0)
579         {
580             status = Cy_SCB_I2C_MasterWriteByte(obj->base, *data, timeout, &obj->context);
581             if (status != CY_SCB_I2C_SUCCESS)
582             {
583                 break;
584             }
585             --size;
586             ++data;
587         }
588     }
589 
590     if (send_stop)
591     {
592         /* SCB in I2C mode is very time sensitive. In practice we have to request STOP after */
593         /* each block, otherwise it may break the transmission */
594         Cy_SCB_I2C_MasterSendStop(obj->base, timeout, &obj->context);
595     }
596 
597     return status;
598 }
599 
cyhal_i2c_master_read(cyhal_i2c_t * obj,uint16_t dev_addr,uint8_t * data,uint16_t size,uint32_t timeout,bool send_stop)600 cy_rslt_t cyhal_i2c_master_read(cyhal_i2c_t *obj, uint16_t dev_addr, uint8_t *data, uint16_t size, uint32_t timeout, bool send_stop)
601 {
602     if (_cyhal_scb_pm_transition_pending())
603         return CYHAL_SYSPM_RSLT_ERR_PM_PENDING;
604 
605     cy_en_scb_i2c_command_t ack = CY_SCB_I2C_ACK;
606 
607     /* Start transaction, send dev_addr */
608     cy_en_scb_i2c_status_t status = obj->context.state == CY_SCB_I2C_IDLE
609         ? Cy_SCB_I2C_MasterSendStart(obj->base, dev_addr, CY_SCB_I2C_READ_XFER, timeout, &obj->context)
610         : Cy_SCB_I2C_MasterSendReStart(obj->base, dev_addr, CY_SCB_I2C_READ_XFER, timeout, &obj->context);
611 
612     if (status == CY_SCB_I2C_SUCCESS)
613     {
614         while (size > 0) {
615             if (size == 1)
616             {
617                 ack = CY_SCB_I2C_NAK;
618             }
619             status = Cy_SCB_I2C_MasterReadByte(obj->base, ack, (uint8_t *)data, timeout, &obj->context);
620             if (status != CY_SCB_I2C_SUCCESS)
621             {
622                 break;
623             }
624             --size;
625             ++data;
626         }
627     }
628 
629     if (send_stop)
630     {
631         /* SCB in I2C mode is very time sensitive. In practice we have to request STOP after */
632         /* each block, otherwise it may break the transmission */
633         Cy_SCB_I2C_MasterSendStop(obj->base, timeout, &obj->context);
634     }
635     return status;
636 }
637 
cyhal_i2c_slave_abort_read(cyhal_i2c_t * obj)638 cy_rslt_t cyhal_i2c_slave_abort_read(cyhal_i2c_t *obj)
639 {
640     cy_rslt_t result = CY_RSLT_SUCCESS;
641 
642     if (obj->context.state == CY_SCB_I2C_IDLE)
643     {
644         Cy_SCB_I2C_SlaveAbortRead(obj->base, &obj->context);
645     }
646     else
647     {
648         result = CYHAL_I2C_RSLT_WARN_DEVICE_BUSY;
649     }
650     return result;
651 }
652 
cyhal_i2c_slave_config_write_buffer(cyhal_i2c_t * obj,const uint8_t * data,uint16_t size)653 cy_rslt_t cyhal_i2c_slave_config_write_buffer(cyhal_i2c_t *obj, const uint8_t *data, uint16_t size)
654 {
655     cy_rslt_t result = CYHAL_I2C_RSLT_ERR_BAD_ARGUMENT;
656     if (size > 0 && data != NULL)
657     {
658         if (obj->context.state == CY_SCB_I2C_IDLE)
659         {
660             Cy_SCB_I2C_SlaveConfigWriteBuf(obj->base, (uint8_t *)data, size, &obj->context);
661             obj->rx_slave_buff.addr.u8 = (uint8_t *)data;
662             obj->rx_slave_buff.size = size;
663             result = CY_RSLT_SUCCESS;
664         }
665         else
666         {
667             result = CYHAL_I2C_RSLT_WARN_DEVICE_BUSY;
668         }
669     }
670     return result;
671 }
672 
cyhal_i2c_slave_config_read_buffer(cyhal_i2c_t * obj,uint8_t * data,uint16_t size)673 cy_rslt_t cyhal_i2c_slave_config_read_buffer(cyhal_i2c_t *obj, uint8_t *data, uint16_t size)
674 {
675     cy_rslt_t result = CYHAL_I2C_RSLT_ERR_BAD_ARGUMENT;
676     if (size > 0 && data != NULL)
677     {
678         if (obj->context.state == CY_SCB_I2C_IDLE)
679         {
680             Cy_SCB_I2C_SlaveConfigReadBuf(obj->base, (uint8_t *)data, size, &obj->context);
681             obj->tx_slave_buff.addr.u8 = data;
682             obj->tx_slave_buff.size = size;
683             result = CY_RSLT_SUCCESS;
684         }
685         else
686         {
687             result = CYHAL_I2C_RSLT_WARN_DEVICE_BUSY;
688         }
689     }
690     return result;
691 }
692 
cyhal_i2c_master_mem_write(cyhal_i2c_t * obj,uint16_t address,uint16_t mem_addr,uint16_t mem_addr_size,const uint8_t * data,uint16_t size,uint32_t timeout)693 cy_rslt_t cyhal_i2c_master_mem_write(cyhal_i2c_t *obj, uint16_t address, uint16_t mem_addr, uint16_t mem_addr_size, const uint8_t *data, uint16_t size, uint32_t timeout)
694 {
695     if (_cyhal_scb_pm_transition_pending())
696         return CYHAL_SYSPM_RSLT_ERR_PM_PENDING;
697 
698     uint8_t mem_addr_buf[2];
699     if (mem_addr_size == 1)
700     {
701         mem_addr_buf[0] = (uint8_t)mem_addr;
702     }
703     else if (mem_addr_size == 2)
704     {
705         mem_addr_buf[0] = (uint8_t)(mem_addr >> 8);
706         mem_addr_buf[1] = (uint8_t)mem_addr;
707     }
708     else
709     {
710         return CYHAL_I2C_RSLT_ERR_INVALID_ADDRESS_SIZE;
711     }
712 
713     cy_rslt_t status = cyhal_i2c_master_write(obj, address, mem_addr_buf, mem_addr_size, timeout, false);
714 
715     if (status == CY_RSLT_SUCCESS)
716     {
717         while (size > 0)
718         {
719             status = Cy_SCB_I2C_MasterWriteByte(obj->base, *data, timeout, &obj->context);
720             if (status != CY_SCB_I2C_SUCCESS)
721             {
722                 break;
723             }
724             --size;
725             ++data;
726         }
727         /* SCB in I2C mode is very time sensitive. In practice we have to request STOP after */
728         /* each block, otherwise it may break the transmission */
729         Cy_SCB_I2C_MasterSendStop(obj->base, timeout, &obj->context);
730     }
731     return status;
732 }
733 
cyhal_i2c_master_mem_read(cyhal_i2c_t * obj,uint16_t address,uint16_t mem_addr,uint16_t mem_addr_size,uint8_t * data,uint16_t size,uint32_t timeout)734 cy_rslt_t cyhal_i2c_master_mem_read(cyhal_i2c_t *obj, uint16_t address, uint16_t mem_addr, uint16_t mem_addr_size, uint8_t *data, uint16_t size, uint32_t timeout)
735 {
736     if (_cyhal_scb_pm_transition_pending())
737         return CYHAL_SYSPM_RSLT_ERR_PM_PENDING;
738 
739     uint8_t mem_addr_buf[2];
740     if (mem_addr_size == 1)
741     {
742         mem_addr_buf[0] = (uint8_t)mem_addr;
743     }
744     else if (mem_addr_size == 2)
745     {
746         mem_addr_buf[0] = (uint8_t)(mem_addr >> 8);
747         mem_addr_buf[1] = (uint8_t)mem_addr;
748     }
749     else
750     {
751         return CYHAL_I2C_RSLT_ERR_INVALID_ADDRESS_SIZE;
752     }
753 
754     cy_rslt_t status = cyhal_i2c_master_write(obj, address, mem_addr_buf, mem_addr_size, timeout, false);
755     if (status == CY_RSLT_SUCCESS)
756     {
757         status = cyhal_i2c_master_read(obj, address, data, size, timeout, true);
758     }
759     return status;
760 }
761 
cyhal_i2c_slave_read(cyhal_i2c_t * obj,uint8_t * dst_buff,uint16_t * size,uint32_t timeout)762 cy_rslt_t cyhal_i2c_slave_read(cyhal_i2c_t *obj, uint8_t *dst_buff, uint16_t *size, uint32_t timeout)
763 {
764     cy_rslt_t status = CYHAL_I2C_RSLT_ERR_BAD_ARGUMENT;
765 
766     if (obj->rx_slave_buff.addr.u8 == NULL)
767     {
768         status = CYHAL_I2C_RSLT_ERR_BUFFERS_NULL_PTR;
769     }
770     else if ((dst_buff != NULL) && (size != NULL))
771     {
772         /* Wait until the master completes writing */
773         status = _cyhal_i2c_slave_wait_for_status(obj, CY_SCB_I2C_SLAVE_WR_CMPLT, timeout);
774 
775         if (CY_RSLT_SUCCESS == status)
776         {
777             *size = _CYHAL_SCB_BYTES_TO_COPY(cyhal_i2c_slave_readable(obj), *size);
778             /* Check if the destination buffer is not a I2C RX buffer. */
779             if (obj->rx_slave_buff.addr.u8 != dst_buff)
780             {
781                 /* Copy command into the destination buffer */
782                 (void) memcpy((void *)dst_buff, (const void *)obj->rx_slave_buff.addr.u8, *size);
783             }
784 
785             /* Wait for device set the state to IDLE */
786             while (obj->context.state != CY_SCB_I2C_IDLE && !(obj->op_in_callback))
787             {
788                 /* I2C PDL driver guarantee the slave will be in IDLE state
789                     after the end of a transaction */
790             }
791 
792             _cyhal_i2c_slave_clear_write_status(obj);
793         }
794     }
795     return status;
796 }
797 
cyhal_i2c_slave_write(cyhal_i2c_t * obj,const uint8_t * src_buff,uint16_t * size,uint32_t timeout)798 cy_rslt_t cyhal_i2c_slave_write(cyhal_i2c_t *obj, const uint8_t *src_buff, uint16_t *size, uint32_t timeout)
799 {
800     cy_rslt_t status = CYHAL_I2C_RSLT_ERR_BAD_ARGUMENT;
801 
802     if (obj->tx_slave_buff.addr.u8 == NULL)
803     {
804         status = CYHAL_I2C_RSLT_ERR_BUFFERS_NULL_PTR;
805     }
806     else if ((src_buff != NULL) && (size != NULL))
807     {
808         /* Wait for completion of a previous Master read transaction */
809         while (obj->context.state != CY_SCB_I2C_IDLE && !(obj->op_in_callback))
810         {
811             /* I2C PDL driver guarantee the slave will be in IDLE state
812                 after the end of a previous transaction */
813         }
814 
815         if (obj->context.state == CY_SCB_I2C_IDLE)
816         {
817             *size = _CYHAL_SCB_BYTES_TO_COPY(obj->tx_slave_buff.size, *size);
818             /* Check if the source buffer is not a I2C TX buffer. */
819             if (obj->tx_slave_buff.addr.u8 != src_buff)
820             {
821                 /* Copy command into the TX buffer */
822                 (void) memcpy((void *)obj->tx_slave_buff.addr.u8, (const void *)src_buff, *size);
823             }
824 
825             /* Wait until the master completes reading */
826             status = _cyhal_i2c_slave_wait_for_status(obj, CY_SCB_I2C_SLAVE_RD_CMPLT, timeout);
827             if (CY_RSLT_SUCCESS == status)
828             {
829                 _cyhal_i2c_slave_clear_read_status(obj);
830             }
831         }
832     }
833     return status;
834 }
835 
cyhal_i2c_master_transfer_async(cyhal_i2c_t * obj,uint16_t address,const void * tx,size_t tx_size,void * rx,size_t rx_size)836 cy_rslt_t cyhal_i2c_master_transfer_async(cyhal_i2c_t *obj, uint16_t address, const void *tx, size_t tx_size, void *rx, size_t rx_size)
837 {
838     if (_cyhal_scb_pm_transition_pending())
839         return CYHAL_SYSPM_RSLT_ERR_PM_PENDING;
840 
841     obj->rx_config.slaveAddress = (uint8_t)address;
842     obj->tx_config.slaveAddress = (uint8_t)address;
843 
844     obj->rx_config.buffer = rx;
845     obj->rx_config.bufferSize = rx_size;
846 
847     obj->tx_config.buffer = (void *)tx;
848     obj->tx_config.bufferSize = tx_size;
849 
850     if (!obj->pending)
851     {
852         /* Validate input data and do appropriate action */
853         if (tx_size)
854         {
855             obj->pending = (rx_size)
856                 ? _CYHAL_I2C_PENDING_TX_RX
857                 : _CYHAL_I2C_PENDING_TX;
858             Cy_SCB_I2C_MasterWrite(obj->base, &obj->tx_config, &obj->context);
859             /* Receive covered by interrupt handler - _cyhal_i2c_irq_handler() */
860         }
861         else if (rx_size)
862         {
863             obj->pending = _CYHAL_I2C_PENDING_RX;
864             Cy_SCB_I2C_MasterRead(obj->base, &obj->rx_config, &obj->context);
865         }
866         else
867         {
868             return CYHAL_I2C_RSLT_ERR_TX_RX_BUFFERS_ARE_EMPTY;
869         }
870     }
871     else
872     {
873         return CYHAL_I2C_RSLT_ERR_PREVIOUS_ASYNCH_PENDING;
874     }
875     return CY_RSLT_SUCCESS;
876 }
877 
cyhal_i2c_abort_async(cyhal_i2c_t * obj)878 cy_rslt_t cyhal_i2c_abort_async(cyhal_i2c_t *obj)
879 {
880     uint16_t timeout_us = 10000;
881     if (obj->pending != _CYHAL_I2C_PENDING_NONE)
882     {
883         if (obj->pending == _CYHAL_I2C_PENDING_RX)
884         {
885             Cy_SCB_I2C_MasterAbortRead(obj->base, &obj->context);
886         }
887         else
888         {
889             Cy_SCB_I2C_MasterAbortWrite(obj->base, &obj->context);
890         }
891         /* After abort, next I2C operation can be initiated only after CY_SCB_I2C_MASTER_BUSY is cleared,
892         *   so waiting for that event to occur. */
893         while ((CY_SCB_I2C_MASTER_BUSY & obj->context.masterStatus) && (timeout_us != 0))
894         {
895             cyhal_system_delay_us(1);
896             timeout_us--;
897         }
898         if (0 == timeout_us)
899         {
900             return CYHAL_I2C_RSLT_ERR_ABORT_ASYNC_TIMEOUT;
901         }
902         obj->pending = _CYHAL_I2C_PENDING_NONE;
903     }
904     return CY_RSLT_SUCCESS;
905 }
906 
cyhal_i2c_register_callback(cyhal_i2c_t * obj,cyhal_i2c_event_callback_t callback,void * callback_arg)907 void cyhal_i2c_register_callback(cyhal_i2c_t *obj, cyhal_i2c_event_callback_t callback, void *callback_arg)
908 {
909     uint32_t savedIntrStatus = cyhal_system_critical_section_enter();
910     obj->callback_data.callback = (cy_israddress) callback;
911     obj->callback_data.callback_arg = callback_arg;
912     cyhal_system_critical_section_exit(savedIntrStatus);
913     Cy_SCB_I2C_RegisterEventCallback(obj->base, _cyhal_i2c_cb_wrapper, &(obj->context));
914 
915     obj->irq_cause = CYHAL_I2C_EVENT_NONE;
916 }
917 
cyhal_i2c_register_address_callback(cyhal_i2c_t * obj,cyhal_i2c_address_callback_t callback,void * callback_arg)918 void cyhal_i2c_register_address_callback(cyhal_i2c_t *obj, cyhal_i2c_address_callback_t callback, void *callback_arg)
919 {
920     uint32_t savedIntrStatus = cyhal_system_critical_section_enter();
921     obj->addr_callback_data.callback = (cy_israddress) callback;
922     obj->addr_callback_data.callback_arg = callback_arg;
923     cyhal_system_critical_section_exit(savedIntrStatus);
924     Cy_SCB_I2C_RegisterAddrCallback(obj->base, _cyhal_i2c_cb_addr_wrapper, &(obj->context));
925 
926     obj->addr_irq_cause = CYHAL_I2C_ADDR_EVENT_NONE;
927 }
928 
cyhal_i2c_enable_event(cyhal_i2c_t * obj,cyhal_i2c_event_t event,uint8_t intr_priority,bool enable)929 void cyhal_i2c_enable_event(cyhal_i2c_t *obj, cyhal_i2c_event_t event, uint8_t intr_priority, bool enable)
930 {
931     uint8_t scb_arr_index = _cyhal_scb_get_block_index(obj->resource.block_num);
932     if (enable)
933     {
934         obj->irq_cause |= event;
935     }
936     else
937     {
938         obj->irq_cause &= ~event;
939     }
940 
941     _cyhal_system_irq_t irqn = _CYHAL_SCB_IRQ_N[scb_arr_index];
942     _cyhal_irq_set_priority(irqn, intr_priority);
943 }
944 
cyhal_i2c_enable_address_event(cyhal_i2c_t * obj,cyhal_i2c_addr_event_t event,uint8_t intr_priority,bool enable)945 void cyhal_i2c_enable_address_event(cyhal_i2c_t *obj, cyhal_i2c_addr_event_t event, uint8_t intr_priority, bool enable)
946 {
947     uint8_t scb_arr_index = _cyhal_scb_get_block_index(obj->resource.block_num);
948     if (enable)
949     {
950         obj->addr_irq_cause |= event;
951     }
952     else
953     {
954         obj->addr_irq_cause &= ~event;
955     }
956 
957     _cyhal_system_irq_t irqn = _CYHAL_SCB_IRQ_N[scb_arr_index];
958     _cyhal_irq_set_priority(irqn, intr_priority);
959 }
960 
cyhal_i2c_set_fifo_level(cyhal_i2c_t * obj,cyhal_i2c_fifo_type_t type,uint16_t level)961 cy_rslt_t cyhal_i2c_set_fifo_level(cyhal_i2c_t *obj, cyhal_i2c_fifo_type_t type, uint16_t level)
962 {
963     return _cyhal_scb_set_fifo_level(obj->base, (cyhal_scb_fifo_type_t)type, level);
964 }
965 
cyhal_i2c_enable_output(cyhal_i2c_t * obj,cyhal_i2c_output_t output,cyhal_source_t * source)966 cy_rslt_t cyhal_i2c_enable_output(cyhal_i2c_t *obj, cyhal_i2c_output_t output, cyhal_source_t *source)
967 {
968     return _cyhal_scb_enable_output(obj->resource, (cyhal_scb_output_t)output, source);
969 }
970 
cyhal_i2c_disable_output(cyhal_i2c_t * obj,cyhal_i2c_output_t output)971 cy_rslt_t cyhal_i2c_disable_output(cyhal_i2c_t *obj, cyhal_i2c_output_t output)
972 {
973     CY_UNUSED_PARAMETER(obj);
974     return _cyhal_scb_disable_output((cyhal_scb_output_t)output);
975 }
976 
cyhal_i2c_slave_readable(cyhal_i2c_t * obj)977 uint32_t cyhal_i2c_slave_readable(cyhal_i2c_t *obj)
978 {
979     return Cy_SCB_I2C_SlaveGetWriteTransferCount(obj->base, &obj->context);
980 }
981 
cyhal_i2c_slave_writable(cyhal_i2c_t * obj)982 uint32_t cyhal_i2c_slave_writable(cyhal_i2c_t *obj)
983 {
984     return (obj->tx_slave_buff.size - Cy_SCB_I2C_SlaveGetReadTransferCount(obj->base, &obj->context));
985 }
986 
cyhal_i2c_clear(cyhal_i2c_t * obj)987 cy_rslt_t cyhal_i2c_clear(cyhal_i2c_t *obj)
988 {
989     Cy_SCB_ClearRxFifo(obj->base);
990     Cy_SCB_ClearTxFifo(obj->base);
991 
992     _cyhal_i2c_slave_clear_write_status(obj);
993     _cyhal_i2c_slave_clear_read_status(obj);
994     return CY_RSLT_SUCCESS;
995 }
996 
997 #if defined(__cplusplus)
998 }
999 #endif
1000 
1001 #endif /* CYHAL_DRIVER_AVAILABLE_I2C */
1002