1 /*
2 * Copyright (c) 2022 Shenzhen Kaihong 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 #ifdef LOSCFG_DRIVERS_HDF_CONFIG_MACRO
17 #include "hcs_macro.h"
18 #include "hdf_config_macro.h"
19 #else
20 #include "device_resource_if.h"
21 #endif
22 #include "hdf_device_desc.h"
23 #include "hdf_log.h"
24 #include "i2c_core.h"
25 #include "i2c_if.h"
26 #include "osal_mem.h"
27 #include "osal_mutex.h"
28 #include "osal_time.h"
29
30 #include "gd32f4xx.h"
31 #include "gd32f4xx_i2c.h"
32
33 #define HDF_LOG_TAG i2c_gd32f4xx
34
35 #define DELAY_MS 1
36 #define TIMEOUT_MS 0xfff
37
38 #define GPIO_PIN_TOTAL 140
39 #define GPIO_REG_STEP 0x00000400
40 #define GPIO_REG_BASE 0x40020000
41 #define GPIO_REG_STEP 0x00000400
42 #define GPIO_BIT_PER_GROUP 16
43
44 #define I2C_BUS_0 0
45 #define I2C_BUS_1 1
46 #define I2C_BUS_2 2
47 #define I2C_FLAG_WRITE 0
48 #define MESSAGE_LAST_SECOND 2
49 #define MESSAGE_LAST_THIRD 3
50 #define US_TO_MS_CONV (1000)
51
I2cMDelay(uint32_t timeOut)52 static void I2cMDelay(uint32_t timeOut)
53 {
54 OsalTimespec startTick = {0, 0};
55 OsalTimespec endTick = {0, 0};
56 OsalTimespec diffTick = {0, 0};
57
58 OsalGetTime(&startTick);
59 do {
60 OsalMSleep(1);
61 /* time out break */
62 OsalGetTime(&endTick);
63 OsalDiffTime(&startTick, &endTick, &diffTick);
64 if ((uint32_t)(diffTick.sec * US_TO_MS_CONV + diffTick.usec / US_TO_MS_CONV) >= timeOut) {
65 break;
66 }
67 } while (true);
68 }
69
I2cTimeOutCheck(void)70 static inline int32_t I2cTimeOutCheck(void)
71 {
72 static int16_t iTmp = 0;
73 I2cMDelay(DELAY_MS);
74 iTmp++;
75 if (iTmp > TIMEOUT_MS) {
76 iTmp = 0;
77 return HDF_ERR_TIMEOUT;
78 }
79 return HDF_SUCCESS;
80 }
81
82 struct I2cDevResource {
83 uint16_t bus;
84 uint16_t scl;
85 uint16_t sda;
86 uint32_t speed;
87 uint32_t regBasePhy;
88 uint32_t rcuGpio;
89 uint32_t rcuI2c;
90 struct OsalMutex mutex;
91 };
92
ToGpioPeriph(uint16_t local)93 static inline uint32_t ToGpioPeriph(uint16_t local)
94 {
95 uint32_t gpioPeriph = 0;
96
97 gpioPeriph = GPIO_REG_BASE + (local / GPIO_BIT_PER_GROUP) * GPIO_REG_STEP;
98
99 return gpioPeriph;
100 }
101
ToGpioPin(uint16_t local)102 static inline uint32_t ToGpioPin(uint16_t local)
103 {
104 uint32_t pinNum = 0;
105
106 pinNum = local % GPIO_BIT_PER_GROUP;
107
108 return (BIT(pinNum));
109 }
110
ToGpioRcu(uint16_t local)111 static inline uint32_t ToGpioRcu(uint16_t local)
112 {
113 uint32_t Periph = 0;
114
115 Periph = local / GPIO_BIT_PER_GROUP;
116
117 return (RCU_GPIOA + Periph);
118 }
119
120 #ifdef LOSCFG_DRIVERS_HDF_CONFIG_MACRO
121 #define I2C_FIND_CONFIG(node, name, resource) \
122 do { \
123 if (strcmp(HCS_PROP(node, match_attr), name) == 0) { \
124 resource->bus = HCS_PROP(node, bus); \
125 resource->speed = HCS_PROP(node, speed); \
126 resource->scl = HCS_PROP(node, scl); \
127 resource->sda = HCS_PROP(node, sda); \
128 result = HDF_SUCCESS; \
129 } \
130 } while (0)
131 #define PLATFORM_CONFIG HCS_NODE(HCS_ROOT, platform)
132 #define PLATFORM_I2C_CONFIG HCS_NODE(HCS_NODE(HCS_ROOT, platform), i2c_config)
GetI2cDeviceResource(struct I2cDevResource * i2cResource,const char * deviceMatchAttr)133 static int32_t GetI2cDeviceResource(struct I2cDevResource *i2cResource, const char *deviceMatchAttr)
134 {
135 int32_t result = HDF_FAILURE;
136 struct I2cDevResource *resource = NULL;
137 if (i2cResource == NULL || deviceMatchAttr == NULL) {
138 HDF_LOGE("device or deviceMatchAttr is NULL\r\n");
139 return HDF_ERR_INVALID_PARAM;
140 }
141 resource = i2cResource;
142 #if HCS_NODE_HAS_PROP(PLATFORM_CONFIG, i2c_config)
143 HCS_FOREACH_CHILD_VARGS(PLATFORM_I2C_CONFIG, I2C_FIND_CONFIG, deviceMatchAttr, resource);
144 #endif
145 if (result != HDF_SUCCESS) {
146 HDF_LOGE("resourceNode %s is NULL\r\n", deviceMatchAttr);
147 }
148
149 return result;
150 }
151 #else
GetI2cDeviceResource(struct I2cDevResource * i2cResource,const struct DeviceResourceNode * resourceNode)152 static int32_t GetI2cDeviceResource(struct I2cDevResource *i2cResource, const struct DeviceResourceNode *resourceNode)
153 {
154 if (i2cResource == NULL || resourceNode == NULL) {
155 HDF_LOGE("[%s]: param is NULL\r\n", __func__);
156 return HDF_ERR_INVALID_PARAM;
157 }
158
159 struct DeviceResourceIface *ops = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);
160 if (ops == NULL || ops->GetUint32 == NULL || ops->GetUint16 == NULL || ops->GetUint16Array == NULL) {
161 HDF_LOGE("DeviceResourceIface is invalid\r\n");
162 return HDF_ERR_INVALID_OBJECT;
163 }
164
165 if (ops->GetUint32(resourceNode, "speed", &i2cResource->speed, 0) != HDF_SUCCESS) {
166 HDF_LOGE("%s: read i2c speed fail!", __func__);
167 return HDF_FAILURE;
168 }
169
170 if (ops->GetUint16(resourceNode, "bus", &i2cResource->bus, 0) != HDF_SUCCESS) {
171 HDF_LOGE("%s: read i2c bus fail!", __func__);
172 return HDF_FAILURE;
173 }
174
175 if (ops->GetUint16(resourceNode, "scl", &i2cResource->scl, 0) != HDF_SUCCESS) {
176 HDF_LOGE("%s: read i2c scl fail!", __func__);
177 return HDF_FAILURE;
178 }
179
180 if (ops->GetUint16(resourceNode, "sda", &i2cResource->sda, 0) != HDF_SUCCESS) {
181 HDF_LOGE("%s: read i2c sda fail!", __func__);
182 return HDF_FAILURE;
183 }
184
185 return HDF_SUCCESS;
186 }
187 #endif
188
I2cParaCheck(struct I2cDevResource * i2cResource)189 static uint32_t I2cParaCheck(struct I2cDevResource *i2cResource)
190 {
191 if (i2cResource->bus != I2C_BUS_0 && i2cResource->bus != I2C_BUS_1 && i2cResource->bus != I2C_BUS_2) {
192 HDF_LOGE("%s: I2c(%d) bus is invalid!", __func__, i2cResource->bus);
193 return HDF_ERR_INVALID_PARAM;
194 }
195
196 if (i2cResource->scl > GPIO_PIN_TOTAL || i2cResource->sda > GPIO_PIN_TOTAL) {
197 HDF_LOGE("%s: I2c(%d) gpio port is invalid!", __func__, i2cResource->bus);
198 return HDF_ERR_INVALID_PARAM;
199 }
200
201 return HDF_SUCCESS;
202 }
203
I2cConfigCompletion(struct I2cDevResource * i2cResource)204 static void I2cConfigCompletion(struct I2cDevResource *i2cResource)
205 {
206 switch (i2cResource->bus) {
207 case I2C_BUS_0:
208 i2cResource->regBasePhy = I2C0;
209 i2cResource->rcuGpio = ToGpioRcu(i2cResource->scl);
210 i2cResource->rcuI2c = RCU_I2C0;
211 break;
212 case I2C_BUS_1:
213 i2cResource->regBasePhy = I2C1;
214 i2cResource->rcuGpio = ToGpioRcu(i2cResource->scl);
215 i2cResource->rcuI2c = RCU_I2C1;
216 break;
217 case I2C_BUS_2:
218 i2cResource->regBasePhy = I2C2;
219 i2cResource->rcuGpio = ToGpioRcu(i2cResource->scl);
220 i2cResource->rcuI2c = RCU_I2C2;
221 break;
222 default:
223 break;
224 }
225
226 return;
227 }
228
AttachI2cDevice(struct I2cCntlr * host,const struct HdfDeviceObject * device)229 static int32_t AttachI2cDevice(struct I2cCntlr *host, const struct HdfDeviceObject *device)
230 {
231 int32_t ret = HDF_FAILURE;
232
233 #ifdef LOSCFG_DRIVERS_HDF_CONFIG_MACRO
234 if (device == NULL || host == NULL) {
235 #else
236 if (device == NULL || device->property == NULL || host == NULL) {
237 #endif
238 HDF_LOGE("[%s]: param is NULL\r\n", __func__);
239 return HDF_ERR_INVALID_PARAM;
240 }
241
242 struct I2cDevResource *i2cResource = (struct I2cDevResource *)OsalMemCalloc(sizeof(struct I2cDevResource));
243 if (i2cResource == NULL) {
244 HDF_LOGE("[%s]: OsalMemCalloc I2cDevResource fail\r\n", __func__);
245 return HDF_ERR_MALLOC_FAIL;
246 }
247
248 #ifdef LOSCFG_DRIVERS_HDF_CONFIG_MACRO
249 ret = GetI2cDeviceResource(i2cResource, device->deviceMatchAttr);
250 #else
251 ret = GetI2cDeviceResource(i2cResource, device->property);
252 #endif
253 if (ret != HDF_SUCCESS || I2cParaCheck(i2cResource) != HDF_SUCCESS) {
254 OsalMemFree(i2cResource);
255 return HDF_FAILURE;
256 }
257 I2cConfigCompletion(i2cResource);
258
259 host->busId = i2cResource->bus;
260 host->priv = i2cResource;
261
262 return HDF_SUCCESS;
263 }
264
265 static void I2cGpioConfig(struct I2cDevResource *i2cResource)
266 {
267 /* enable GPIOB clock */
268 rcu_periph_clock_enable(i2cResource->rcuGpio);
269 /* enable I2C0 clock */
270 rcu_periph_clock_enable(i2cResource->rcuI2c);
271
272 /* connect PB6 to I2C0_SCL */
273 gpio_af_set(ToGpioPeriph(i2cResource->scl), GPIO_AF_4, ToGpioPin(i2cResource->scl));
274 /* connect PB7 to I2C0_SDA */
275 gpio_af_set(ToGpioPeriph(i2cResource->sda), GPIO_AF_4, ToGpioPin(i2cResource->sda));
276
277 gpio_mode_set(ToGpioPeriph(i2cResource->scl), GPIO_MODE_AF, GPIO_PUPD_PULLUP, ToGpioPin(i2cResource->scl));
278 gpio_output_options_set(ToGpioPeriph(i2cResource->scl), GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ,
279 ToGpioPin(i2cResource->scl));
280 gpio_mode_set(ToGpioPeriph(i2cResource->sda), GPIO_MODE_AF, GPIO_PUPD_PULLUP, ToGpioPin(i2cResource->sda));
281 gpio_output_options_set(ToGpioPeriph(i2cResource->sda), GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ,
282 ToGpioPin(i2cResource->sda));
283 }
284
285 static void I2cConfig(struct I2cDevResource *i2cResource)
286 {
287 /* configure I2C clock */
288 i2c_clock_config(i2cResource->regBasePhy, i2cResource->speed, I2C_DTCY_2);
289 /* enable I2C0 */
290 i2c_enable(i2cResource->regBasePhy);
291 /* enable acknowledge */
292 i2c_ack_config(i2cResource->regBasePhy, I2C_ACK_ENABLE);
293 }
294
295 static uint32_t Gd32f4xxI2cWrite(struct I2cDevResource *device, struct I2cMsg *msg)
296 {
297 uint16_t bufIdx = 0;
298 uint8_t val;
299 /* 等待总线空闲 */
300 while (i2c_flag_get(device->regBasePhy, I2C_FLAG_I2CBSY) && !I2cTimeOutCheck()) { }
301 if (!(msg->flags & I2C_FLAG_NO_START)) {
302 /* 发送start信号 */
303 i2c_start_on_bus(device->regBasePhy);
304 while (!i2c_flag_get(device->regBasePhy, I2C_FLAG_SBSEND) && !I2cTimeOutCheck()) { }
305 }
306 /* 设置从机地址操作 */
307 i2c_master_addressing(device->regBasePhy, msg->addr, I2C_TRANSMITTER);
308 /* 等待从机地址发送标志 */
309 while (!i2c_flag_get(device->regBasePhy, I2C_FLAG_ADDSEND) && !I2cTimeOutCheck()) { }
310 /* 清除从机地址发送标志 */
311 i2c_flag_clear(device->regBasePhy, I2C_FLAG_ADDSEND);
312 while (!i2c_flag_get(device->regBasePhy, I2C_FLAG_TBE) && !I2cTimeOutCheck()) { }
313 while (bufIdx < msg->len) {
314 val = msg->buf[bufIdx];
315 i2c_data_transmit(device->regBasePhy, val);
316 bufIdx++;
317 /* 等待数据寄存器空 */
318 while (!i2c_flag_get(device->regBasePhy, I2C_FLAG_BTC) && !I2cTimeOutCheck()) { }
319 }
320
321 if (msg->flags & I2C_FLAG_STOP) {
322 /* 发送stop信号 */
323 i2c_stop_on_bus(device->regBasePhy);
324 while ((I2C_CTL0(device->regBasePhy) & I2C_CTL0_STOP) && !I2cTimeOutCheck()) { }
325 }
326
327 return HDF_SUCCESS;
328 }
329
330 static int Gd32f4xxI2cRead(struct I2cDevResource *device, struct I2cMsg *msg)
331 {
332 uint16_t bufIdx = 0;
333 uint8_t val;
334 /* 等待总线空闲 */
335 while (i2c_flag_get(device->regBasePhy, I2C_FLAG_I2CBSY) && !I2cTimeOutCheck()) { }
336 if (msg->len == MESSAGE_LAST_SECOND) {
337 /* 接收数据长度等于2时,首先将POAP置1 */
338 i2c_ackpos_config(device->regBasePhy, I2C_ACKPOS_NEXT);
339 }
340
341 if (!(msg->flags & I2C_FLAG_NO_START)) {
342 i2c_start_on_bus(device->regBasePhy);
343 /* 等待SBSEND标志 */
344 while (!i2c_flag_get(device->regBasePhy, I2C_FLAG_SBSEND) && !I2cTimeOutCheck()) { }
345 }
346
347 i2c_master_addressing(device->regBasePhy, msg->addr, I2C_RECEIVER);
348 if (msg->len < MESSAGE_LAST_THIRD) {
349 /* 接收数据长度小于3时,需先清除ACK */
350 i2c_ack_config(device->regBasePhy, I2C_ACK_DISABLE);
351 }
352 /* 等待从机地址发送标志 */
353 while (!i2c_flag_get(device->regBasePhy, I2C_FLAG_ADDSEND) && !I2cTimeOutCheck()) { }
354 /* 清除从机地址发送标志 */
355 i2c_flag_clear(device->regBasePhy, I2C_FLAG_ADDSEND);
356 while (bufIdx < msg->len) {
357 /* 等待倒数第二个数据被接收到寄存器 */
358 if (msg->len - bufIdx == MESSAGE_LAST_THIRD) {
359 while (!i2c_flag_get(device->regBasePhy, I2C_FLAG_BTC) && !I2cTimeOutCheck()) { }
360 /* 清除ACK */
361 i2c_ack_config(device->regBasePhy, I2C_ACK_DISABLE);
362 }
363 if (msg->len - bufIdx == MESSAGE_LAST_SECOND) {
364 while (!i2c_flag_get(device->regBasePhy, I2C_FLAG_BTC) && !I2cTimeOutCheck()) { }
365 if (msg->flags & I2C_FLAG_STOP) {
366 i2c_stop_on_bus(device->regBasePhy);
367 }
368 }
369 /* 等待RBNE位被设置 */
370 if (i2c_flag_get(device->regBasePhy, I2C_FLAG_RBNE)) {
371 /* 从I2C总线读取数据 */
372 val = i2c_data_receive(device->regBasePhy);
373 msg->buf[bufIdx] = val;
374 bufIdx++;
375 }
376 }
377
378 if (msg->flags & I2C_FLAG_STOP) {
379 while ((I2C_CTL0(device->regBasePhy) & I2C_CTL0_STOP) && !I2cTimeOutCheck()) { }
380 }
381
382 i2c_ack_config(device->regBasePhy, I2C_ACK_ENABLE);
383 return HDF_SUCCESS;
384 }
385
386 static int32_t I2cDataTransfer(struct I2cCntlr *cntlr, struct I2cMsg *msgs, int16_t count)
387 {
388 int32_t i = 0;
389 int32_t ret;
390
391 if (cntlr == NULL || msgs == NULL || cntlr->priv == NULL) {
392 HDF_LOGE("[%s]: I2cDataTransfer param is NULL!\r\n", __func__);
393 return HDF_ERR_INVALID_PARAM;
394 }
395 if (count <= 0) {
396 HDF_LOGE("[%s]: I2c msg count err\r\n", __func__);
397 return HDF_ERR_INVALID_PARAM;
398 }
399
400 struct I2cDevResource *device = (struct I2cDevResource *)cntlr->priv;
401 if (device == NULL) {
402 HDF_LOGE("%s: I2c device is NULL\r\n", __func__);
403 return HDF_DEV_ERR_NO_DEVICE;
404 }
405
406 struct I2cMsg *msg = NULL;
407 if (HDF_SUCCESS != OsalMutexLock(&device->mutex)) {
408 HDF_LOGE("[%s]: OsalMutexLock fail\r\n", __func__);
409 return HDF_ERR_TIMEOUT;
410 }
411
412 for (i = 0; i < count; i++) {
413 msg = &msgs[i];
414 if (msg->flags & (I2C_FLAG_ADDR_10BIT | I2C_FLAG_READ_NO_ACK | I2C_FLAG_IGNORE_NO_ACK | I2C_FLAG_NO_START)) {
415 HDF_LOGE("%s: flag %d is not support", __func__, msg->flags);
416 } else if (msg->flags == (I2C_FLAG_READ | I2C_FLAG_STOP)) {
417 ret = Gd32f4xxI2cRead(device, msg);
418 } else if (msg->flags == I2C_FLAG_STOP) {
419 ret = Gd32f4xxI2cWrite(device, msg);
420 }
421 if (ret != HDF_SUCCESS) {
422 HDF_LOGE("%s: I2c transfer fail!,flag :%d", __func__, msg->flags);
423 break;
424 }
425 }
426 OsalMutexUnlock(&device->mutex);
427
428 return i;
429 }
430
431 static const struct I2cMethod g_I2cMethod = {
432 .transfer = I2cDataTransfer,
433 };
434
435 static int32_t I2cDriverBind(struct HdfDeviceObject *device)
436 {
437 if (device == NULL) {
438 HDF_LOGE("[%s]: I2c device is NULL\r\n", __func__);
439 return HDF_FAILURE;
440 }
441 return HDF_SUCCESS;
442 }
443
444 static void I2cDriverRelease(struct HdfDeviceObject *device)
445 {
446 struct I2cCntlr *i2cCntrl = NULL;
447 struct I2cDevResource *i2cDevice = NULL;
448
449 HDF_LOGI("%s: enter", __func__);
450
451 if (device == NULL) {
452 HDF_LOGE("%s: device is NULL", __func__);
453 return;
454 }
455
456 i2cCntrl = device->priv;
457 if (i2cCntrl == NULL || i2cCntrl->priv == NULL) {
458 HDF_LOGE("%s: i2cCntrl is NULL\r\n", __func__);
459 return;
460 }
461 i2cCntrl->ops = NULL;
462
463 i2cDevice = (struct I2cDevResource *)i2cCntrl->priv;
464
465 if (i2cDevice != NULL) {
466 OsalMutexDestroy(&i2cDevice->mutex);
467 OsalMemFree(i2cDevice);
468 }
469 OsalMemFree(i2cCntrl);
470
471 return;
472 }
473
474 static int32_t I2cDriverInit(struct HdfDeviceObject *device)
475 {
476 int32_t ret = HDF_FAILURE;
477 struct I2cCntlr *host = NULL;
478
479 if (device == NULL) {
480 HDF_LOGE("%s: device or property is NULL", __func__);
481 return HDF_ERR_INVALID_OBJECT;
482 }
483 HDF_LOGI("%s: Enter", __func__);
484
485 host = (struct I2cCntlr *)OsalMemCalloc(sizeof(struct I2cCntlr));
486 if (host == NULL) {
487 HDF_LOGE("[%s]: malloc host is NULL\r\n", __func__);
488 return HDF_ERR_MALLOC_FAIL;
489 }
490
491 host->ops = &g_I2cMethod;
492 device->priv = (void *)host;
493
494 ret = AttachI2cDevice(host, device);
495 if (ret != HDF_SUCCESS) {
496 HDF_LOGE("[%s]: AttachI2cDevice error, ret = %d\r\n", __func__, ret);
497 I2cDriverRelease(device);
498 return HDF_DEV_ERR_ATTACHDEV_FAIL;
499 }
500
501 /* configure GPIO */
502 I2cGpioConfig((struct I2cDevResource *)host->priv);
503
504 /* configure I2C */
505 I2cConfig((struct I2cDevResource *)host->priv);
506
507 ret = I2cCntlrAdd(host);
508 if (ret != HDF_SUCCESS) {
509 I2cDriverRelease(device);
510 return HDF_FAILURE;
511 }
512 HDF_LOGI("%s: i2c%d init success", __func__, host->busId);
513 return HDF_SUCCESS;
514 }
515
516 struct HdfDriverEntry g_i2cDriverEntry = {
517 .moduleVersion = 1,
518 .Bind = I2cDriverBind,
519 .Init = I2cDriverInit,
520 .Release = I2cDriverRelease,
521 .moduleName = "GD_I2C_MODULE_HDF",
522 };
523 HDF_INIT(g_i2cDriverEntry);
524