1 /*
2  * Arm SCP/MCP Software
3  * Copyright (c) 2018-2022, Arm Limited and Contributors. All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  */
7 
8 #include <i2c_api.h>
9 
10 #include <internal/i2c_depend.h>
11 #include <internal/i2c_driver.h>
12 
13 #include <stdbool.h>
14 #include <stdio.h>
15 
16 #define FILE_GRP_ID DBG_DRV_I2C
17 #define CONTROLLER_CODE_VAL 0x04
18 
19 static I2C_ERR_t i2c_api_recv_data_i(
20     I2C_EN_CH_t ch,
21     uint32_t target_address,
22     uint32_t address,
23     uint8_t *data,
24     int length,
25     int flgid);
26 
27 static I2C_ERR_t i2c_api_send_data_i(
28     I2C_EN_CH_t ch,
29     uint32_t target_address,
30     uint32_t address,
31     const uint8_t *data,
32     int length,
33     int flgid);
34 
f_i2c_api_initialize(I2C_ST_PACKET_INFO_t * packet_info,uint32_t reg_base,I2C_TYPE type,const I2C_PARAM_t * param)35 I2C_ERR_t f_i2c_api_initialize(
36     I2C_ST_PACKET_INFO_t *packet_info,
37     uint32_t reg_base,
38     I2C_TYPE type,
39     const I2C_PARAM_t *param)
40 {
41     I2C_ERR_t ercd = I2C_ERR_OK;
42     ercd = i2c_initialize(packet_info, reg_base, type, param);
43     return ercd;
44 }
45 
i2c_api_use_hs_mode(I2C_EN_CH_t ch,bool use_hsmode_flag)46 I2C_ERR_t i2c_api_use_hs_mode(I2C_EN_CH_t ch, bool use_hsmode_flag)
47 {
48     I2C_ST_PACKET_INFO_t *packet_info = i2c_get_channel_structure(ch);
49 
50     if (packet_info == NULL)
51         return I2C_ERR_PARAM;
52 
53     if (packet_info->TYPE != I2C_TYPE_F_I2C_SP1)
54         return I2C_ERR_UNAVAILABLE;
55 
56     packet_info->USE_HS_MODE = use_hsmode_flag;
57     return I2C_ERR_OK;
58 }
59 
i2c_api_recv_data_i(I2C_EN_CH_t ch,uint32_t target_address,uint32_t address,uint8_t * data,int length,int flgid)60 static I2C_ERR_t i2c_api_recv_data_i(
61     I2C_EN_CH_t ch,
62     uint32_t target_address,
63     uint32_t address,
64     uint8_t *data,
65     int length,
66     int flgid)
67 {
68     I2C_ERR_t ercd = I2C_ERR_OK;
69     I2C_ST_PACKET_INFO_t *packet_info = i2c_get_channel_structure(ch);
70 
71     if (packet_info == NULL)
72         return I2C_ERR_PARAM;
73 
74     i2c_enable(packet_info);
75 
76     i2c_packet_initialize(&packet_info->PACKET);
77 
78     /* Send controller code, only for F_I2C_SP1 */
79     if (packet_info->TYPE == I2C_TYPE_F_I2C_SP1) {
80         if (packet_info->USE_HS_MODE) {
81             packet_info->CONTROLLER_CODE_FLAG = true;
82             i2c_packet_set_control(
83                 &packet_info->PACKET, CONTROLLER_CODE_VAL, false);
84         }
85     }
86 
87     i2c_packet_set_control(&packet_info->PACKET, target_address, false);
88     i2c_packet_set_address(&packet_info->PACKET, address, 1);
89     i2c_packet_set_control(&packet_info->PACKET, target_address, true);
90     i2c_packet_set_payload(&packet_info->PACKET, (char *)data, length);
91 
92     ercd = i2c_exec_transfer(packet_info);
93     if ((flgid == 0) && (ercd == I2C_ERR_OK))
94         ercd = i2c_handler_polling(packet_info);
95 
96     i2c_disable(packet_info);
97 
98     return ercd;
99 }
100 
f_i2c_api_recv_data(I2C_EN_CH_t ch,uint32_t target_address,uint32_t address,uint8_t * data,int length)101 I2C_ERR_t f_i2c_api_recv_data(
102     I2C_EN_CH_t ch,
103     uint32_t target_address,
104     uint32_t address,
105     uint8_t *data,
106     int length)
107 {
108     I2C_ERR_t ercd = I2C_ERR_OK;
109 
110     if ((target_address <= 0x03) || (target_address >= 0x78))
111         return I2C_ERR_PARAM;
112 
113     if (data == NULL)
114         return I2C_ERR_PARAM;
115 
116     if (length <= 0)
117         return I2C_ERR_PARAM;
118 
119     ercd = i2c_api_recv_data_i(
120         ch, target_address, address, data, length, 0x00000000);
121 
122     return ercd;
123 }
124 
i2c_api_send_data_i(I2C_EN_CH_t ch,uint32_t target_address,uint32_t address,const uint8_t * data,int length,int flgid)125 static I2C_ERR_t i2c_api_send_data_i(
126     I2C_EN_CH_t ch,
127     uint32_t target_address,
128     uint32_t address,
129     const uint8_t *data,
130     int length,
131     int flgid)
132 {
133     I2C_ERR_t ercd = I2C_ERR_OK;
134     I2C_ST_PACKET_INFO_t *packet_info = i2c_get_channel_structure(ch);
135 
136     if (packet_info == NULL)
137         return I2C_ERR_PARAM;
138 
139     i2c_enable(packet_info);
140 
141     i2c_packet_initialize(&packet_info->PACKET);
142 
143     /* Send controller code, only for F_I2C_SP1 */
144     if (packet_info->TYPE == I2C_TYPE_F_I2C_SP1) {
145         if (packet_info->USE_HS_MODE) {
146             packet_info->CONTROLLER_CODE_FLAG = true;
147             i2c_packet_set_control(
148                 &packet_info->PACKET, CONTROLLER_CODE_VAL, false);
149         }
150     }
151 
152     i2c_packet_set_control(&packet_info->PACKET, target_address, false);
153     i2c_packet_set_address(&packet_info->PACKET, address, 1);
154     i2c_packet_set_payload(&packet_info->PACKET, (char *)data, length);
155 
156     ercd = i2c_exec_transfer(packet_info);
157     if ((flgid == 0) && (ercd == I2C_ERR_OK))
158         ercd = i2c_handler_polling(packet_info);
159 
160     i2c_disable(packet_info);
161 
162     return ercd;
163 }
164 
f_i2c_api_send_data(I2C_EN_CH_t ch,uint32_t target_address,uint32_t address,const uint8_t * data,int length)165 I2C_ERR_t f_i2c_api_send_data(
166     I2C_EN_CH_t ch,
167     uint32_t target_address,
168     uint32_t address,
169     const uint8_t *data,
170     int length)
171 {
172     I2C_ERR_t ercd = I2C_ERR_OK;
173 
174     if ((target_address == 0x01) || (target_address == 0x02) ||
175         (target_address == 0x03) || (target_address >= 0x78)) {
176         return I2C_ERR_PARAM;
177     }
178 
179     if (length < 0)
180         return I2C_ERR_PARAM;
181 
182     ercd = i2c_api_send_data_i(
183         ch, target_address, address, data, length, 0x00000000);
184 
185     return ercd;
186 }
187