1 /*
2 * Copyright (c) 2022 Hunan OpenValley Digital Industry Development Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <stdlib.h>
17 #include "hcs_macro.h"
18 #include "hdf_config_macro.h"
19 #include "hdf_device_desc.h"
20 #include "hdf_log.h"
21 #include "i2c_core.h"
22 #include "i2c_if.h"
23 #include "osal_mutex.h"
24 #include "driver/i2c.h"
25
26 #define HDF_LOG_TAG "ESP32U4_HDF_I2C"
27
28 struct RealI2cResource {
29 uint8_t port; // I2C端口号
30 uint8_t mode; // I2C主从模式 0:master 1:slave
31 uint8_t scl_pin; // SCL引脚号
32 uint8_t sda_pin; // SDA引脚号
33 uint32_t speed; // I2C时钟频率
34 };
35
36 static int32_t I2cDriverBind(struct HdfDeviceObject *device);
37 static int32_t I2cDriverInit(struct HdfDeviceObject *device);
38 static void I2cDriverRelease(struct HdfDeviceObject *device);
39 static int32_t I2cDataTransfer(struct I2cCntlr *cntlr, struct I2cMsg *msgs, int16_t count);
40
41 struct HdfDriverEntry gI2cHdfDriverEntry = {
42 .moduleVersion = 1,
43 .moduleName = "ESP32U4_HDF_I2C",
44 .Bind = I2cDriverBind,
45 .Init = I2cDriverInit,
46 .Release = I2cDriverRelease,
47 };
48 HDF_INIT(gI2cHdfDriverEntry);
49
50 struct I2cMethod gI2cHostMethod = {
51 .transfer = I2cDataTransfer,
52 };
53
54 #define I2C_FIND_CONFIG(node, name, resource) \
55 do { \
56 if (strcmp(HCS_PROP(node, match_attr), name) == 0) { \
57 (resource)->mode = HCS_PROP(node, mode); \
58 (resource)->port = HCS_PROP(node, port); \
59 (resource)->scl_pin = HCS_PROP(node, scl_pin); \
60 (resource)->sda_pin = HCS_PROP(node, sda_pin); \
61 (resource)->speed = HCS_PROP(node, speed); \
62 HDF_LOGE("----- I2C%d Config -----", (resource)->port); \
63 HDF_LOGE("mode = %d", (resource)->mode); \
64 HDF_LOGE("scl_pin = %d", (resource)->scl_pin); \
65 HDF_LOGE("sda_pin = %d", (resource)->sda_pin); \
66 HDF_LOGE("speed = %d", (resource)->speed); \
67 result = HDF_SUCCESS; \
68 } \
69 } while (0)
70 #define PLATFORM_CONFIG HCS_NODE(HCS_ROOT, platform)
71 #define PLATFORM_I2C_CONFIG HCS_NODE(HCS_NODE(HCS_ROOT, platform), i2c_config)
GetI2cDeviceResource(struct RealI2cResource * i2cResource,const char * deviceMatchAttr)72 static uint32_t GetI2cDeviceResource(struct RealI2cResource *i2cResource, const char *deviceMatchAttr)
73 {
74 int32_t result = HDF_FAILURE;
75 struct RealI2cResource *resource = NULL;
76 if (i2cResource == NULL || deviceMatchAttr == NULL) {
77 HDF_LOGE("device or deviceMatchAttr is NULL\r\n");
78 return HDF_ERR_INVALID_PARAM;
79 }
80 resource = i2cResource;
81 #if HCS_NODE_HAS_PROP(PLATFORM_CONFIG, i2c_config)
82 HCS_FOREACH_CHILD_VARGS(PLATFORM_I2C_CONFIG, I2C_FIND_CONFIG, deviceMatchAttr, resource);
83 #endif
84 if (result != HDF_SUCCESS) {
85 HDF_LOGE("resourceNode %s is NULL\r\n", deviceMatchAttr);
86 }
87 return result;
88 }
89 #define TICKS_SECOND 1000
DeviceI2cWrite(int id,unsigned char addr,const unsigned char * data,unsigned int dataLen,int ack)90 unsigned int DeviceI2cWrite(int id, unsigned char addr, const unsigned char *data, unsigned int dataLen, int ack)
91 {
92 unsigned int ret;
93 i2c_cmd_handle_t cmd;
94 if (dataLen < 1) {
95 return 0;
96 }
97 cmd = i2c_cmd_link_create();
98 if ((ret = i2c_master_start(cmd)) != 0) {
99 HDF_LOGE("DeviceI2cWrite i2c_master_start failed ret = %x", ret);
100 return ret;
101 }
102 if ((ret = i2c_master_write_byte(cmd, addr | 0x00, ack)) != 0) {
103 HDF_LOGE("DeviceI2cWrite i2c_master_write_addr failed ret = %x", ret);
104 return ret;
105 }
106
107 if ((ret = i2c_master_write(cmd, data, dataLen, 1)) != 0) {
108 HDF_LOGE("DeviceI2cWrite i2c_master_write failed ret = %x", ret);
109 return ret;
110 }
111
112 if ((ret = i2c_master_stop(cmd)) != 0) {
113 HDF_LOGE("DeviceI2cWrite i2c_master_stop failed ret = %x", ret);
114 return ret;
115 }
116 if ((ret = i2c_master_cmd_begin(id, cmd, TICKS_SECOND / portTICK_RATE_MS)) != 0) {
117 HDF_LOGE("DeviceI2cWrite i2c_master_cmd_begin failed ret = %d", ret);
118 return ret;
119 }
120 i2c_cmd_link_delete(cmd);
121 return ret;
122 }
123
DeviceI2cRead(int id,unsigned char addr,const unsigned char * data,unsigned int dataLen,int ack)124 unsigned int DeviceI2cRead(int id, unsigned char addr, const unsigned char *data, unsigned int dataLen, int ack)
125 {
126 unsigned int ret;
127 i2c_cmd_handle_t cmd;
128 if (dataLen < 1) {
129 return 0;
130 }
131 cmd = i2c_cmd_link_create();
132 if ((ret = i2c_master_start(cmd)) != 0) {
133 HDF_LOGE("DeviceI2cRead i2c_master_start failed ret = %x", ret);
134 return ret;
135 }
136
137 if ((ret = i2c_master_write_byte(cmd, addr | 0x01, ack)) != 0) {
138 HDF_LOGE("DeviceI2cRead i2c_master_write_addr failed ret = %x", ret);
139 return ret;
140 }
141
142 if (dataLen > 1) {
143 if ((ret = i2c_master_read(cmd, data, dataLen - 1, 0)) != 0) {
144 HDF_LOGE("DeviceI2cRead i2c_master_read failed ret = %x", ret);
145 return ret;
146 }
147 }
148
149 if ((ret = i2c_master_read_byte(cmd, data + dataLen - 1, 1)) != 0) {
150 HDF_LOGE("DeviceI2cRead i2c_master_read_byte failed ret = %x", ret);
151 return ret;
152 }
153
154 if ((ret = i2c_master_stop(cmd)) != 0) {
155 HDF_LOGE("DeviceI2cRead i2c_master_stop failed ret = %x", ret);
156 return ret;
157 }
158
159 if ((ret = i2c_master_cmd_begin(id, cmd, TICKS_SECOND / portTICK_RATE_MS)) != 0) {
160 HDF_LOGE("DeviceI2cRead i2c_master_cmd_begin failed ret = %x", ret);
161 return ret;
162 }
163 i2c_cmd_link_delete(cmd);
164 return ret;
165 }
166 #define MODE2 2
167 #define MODE4 4
DeviceI2cInit(int id,int scl_pin,int sda_pin,int speed,int mode)168 static int DeviceI2cInit(int id, int scl_pin, int sda_pin, int speed, int mode)
169 {
170 i2c_config_t conf;
171 (void)memset_s(&conf, sizeof(conf), 0, sizeof(conf));
172 conf.mode = (mode & 1) ? I2C_MODE_SLAVE : I2C_MODE_MASTER;
173 conf.sda_io_num = sda_pin;
174 conf.scl_io_num = scl_pin;
175 conf.sda_pullup_en = (mode & MODE2) ? GPIO_PULLUP_ENABLE : GPIO_PULLUP_DISABLE;
176 conf.scl_pullup_en = (mode & MODE4) ? GPIO_PULLUP_ENABLE : GPIO_PULLUP_DISABLE;
177 conf.master.clk_speed = speed;
178 i2c_param_config(id, &conf);
179 return i2c_driver_install(id, conf.mode, 0, 0, 0);
180 }
181
AttachI2cDevice(struct I2cCntlr * host,struct HdfDeviceObject * device)182 static int32_t AttachI2cDevice(struct I2cCntlr *host, struct HdfDeviceObject *device)
183 {
184 int32_t ret = HDF_FAILURE;
185
186 if (host == NULL || device == NULL) {
187 HDF_LOGE("[%s]: param is NULL\r\n", __func__);
188 return HDF_ERR_INVALID_PARAM;
189 }
190
191 struct RealI2cResource *i2cResource = (struct RealI2cResource *)OsalMemAlloc(sizeof(struct RealI2cResource));
192 if (i2cResource == NULL) {
193 HDF_LOGE("[%s]: OsalMemAlloc RealI2cResource fail\r\n", __func__);
194 return HDF_ERR_MALLOC_FAIL;
195 }
196 memset_s(i2cResource, sizeof(struct RealI2cResource), 0, sizeof(struct RealI2cResource));
197
198 ret = GetI2cDeviceResource(i2cResource, device->deviceMatchAttr);
199
200 DeviceI2cInit(i2cResource->port, i2cResource->scl_pin, i2cResource->sda_pin,
201 i2cResource->speed, i2cResource->mode);
202
203 if (ret != HDF_SUCCESS) {
204 OsalMemFree(i2cResource);
205 return HDF_FAILURE;
206 }
207
208 host->busId = i2cResource->port;
209 host->priv = i2cResource;
210
211 return HDF_SUCCESS;
212 }
213
I2cDataTransfer(struct I2cCntlr * cntlr,struct I2cMsg * msgs,int16_t count)214 static int32_t I2cDataTransfer(struct I2cCntlr *cntlr, struct I2cMsg *msgs, int16_t count)
215 {
216 unsigned int ret;
217 if (cntlr == NULL || msgs == NULL || cntlr->priv == NULL) {
218 HDF_LOGE("[%s]: I2cDataTransfer param is NULL\r\n", __func__);
219 return HDF_ERR_INVALID_PARAM;
220 }
221
222 if (count <= 0) {
223 HDF_LOGE("[%s]: I2cDataTransfer count err\r\n", __func__);
224 return HDF_ERR_INVALID_PARAM;
225 }
226
227 struct RealI2cResource *device = (struct I2cDevice *)cntlr->priv;
228 if (device == NULL) {
229 HDF_LOGE("%s: I2cDevice is NULL\r\n", __func__);
230 return HDF_DEV_ERR_NO_DEVICE;
231 }
232
233 for (; count > 0; --count, ++msgs) {
234 if ((msgs->flags) == 0) { // write
235 if (DeviceI2cWrite(cntlr->busId, msgs->addr, msgs->buf, msgs->len, 1))
236 break;
237 } else if ((msgs->flags) == I2C_FLAG_READ) { // read
238 if (DeviceI2cRead(cntlr->busId, msgs->addr, msgs->buf, msgs->len, 1))
239 break;
240 }
241 }
242 return count;
243 }
244
I2cDriverBind(struct HdfDeviceObject * device)245 static int32_t I2cDriverBind(struct HdfDeviceObject *device)
246 {
247 return HDF_SUCCESS;
248 }
249
I2cDriverInit(struct HdfDeviceObject * device)250 static int32_t I2cDriverInit(struct HdfDeviceObject *device)
251 {
252 int32_t ret = HDF_FAILURE;
253 struct I2cCntlr *host = NULL;
254 if (device == NULL) {
255 HDF_LOGE("[%s]: I2c device is NULL\r\n", __func__);
256 return HDF_ERR_INVALID_PARAM;
257 }
258
259 host = (struct I2cCntlr *)OsalMemAlloc(sizeof(struct I2cCntlr));
260 if (host == NULL) {
261 HDF_LOGE("[%s]: malloc host is NULL\r\n", __func__);
262 return HDF_ERR_MALLOC_FAIL;
263 }
264
265 memset_s(host, sizeof(struct I2cCntlr), 0, sizeof(struct I2cCntlr));
266 host->ops = &gI2cHostMethod;
267 device->priv = (VOID *)host;
268
269 ret = AttachI2cDevice(host, device);
270 if (ret != HDF_SUCCESS) {
271 HDF_LOGE("[%s]: AttachI2cDevice error, ret = %d\r\n", __func__, ret);
272 I2cDriverRelease(device);
273 return HDF_DEV_ERR_ATTACHDEV_FAIL;
274 }
275
276 ret = I2cCntlrAdd(host);
277 if (ret != HDF_SUCCESS) {
278 I2cDriverRelease(device);
279 return HDF_FAILURE;
280 }
281 HDF_LOGI("I2cDriverInit success!!");
282 return HDF_SUCCESS;
283 }
284
I2cDriverRelease(struct HdfDeviceObject * device)285 static void I2cDriverRelease(struct HdfDeviceObject *device)
286 {
287 if (device == NULL) {
288 HDF_LOGE("%s: device is NULL\r\n", __func__);
289 return;
290 }
291
292 struct I2cCntlr *i2cCntrl = device->priv;
293 if (i2cCntrl == NULL || i2cCntrl->priv == NULL) {
294 HDF_LOGE("%s: i2cCntrl is NULL\r\n", __func__);
295 return;
296 }
297 i2cCntrl->ops = NULL;
298 struct RealI2cResource *i2cDevice = (struct I2cDevice *)i2cCntrl->priv;
299 OsalMemFree(i2cCntrl);
300
301 if (i2cDevice != NULL) {
302 OsalMemFree(i2cDevice);
303 }
304 }
305