• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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