1 /*
2  * Copyright (c) 2022 Talkweb Co., Ltd.
3  *
4  * HDF is dual licensed: you can use it either under the terms of
5  * the GPL, or the BSD license, at your option.
6  * See the LICENSE file in the root of this repository for complete details.
7  */
8 
9 #include <stdlib.h>
10 #ifdef LOSCFG_DRIVERS_HDF_CONFIG_MACRO
11 #include "hcs_macro.h"
12 #include "hdf_config_macro.h"
13 #else
14 #include "device_resource_if.h"
15 #endif
16 #include "hdf_device_desc.h"
17 #include "hdf_log.h"
18 #include "i2c_core.h"
19 #include "i2c_if.h"
20 #include "osal_mutex.h"
21 #include "hdf_base_hal.h"
22 #include "stm32f4xx_ll_i2c.h"
23 
24 #define HDF_LOG_TAG "hdf_i2c"
25 
26 typedef enum {
27     I2C_HANDLE_NULL = 0,
28     I2C_HANDLE_1 = 1,
29     I2C_HANDLE_2 = 2,
30     I2C_HANDLE_3 = 3,
31     I2C_HANDLE_MAX = I2C_HANDLE_3
32 } I2C_HANDLE;
33 
34 struct RealI2cResource {
35     uint8_t port;
36     uint8_t devMode;
37     uint32_t devAddr;
38     uint32_t speed;
39     struct OsalMutex mutex;
40 };
41 
42 static bool g_I2cEnableFlg[I2C_HANDLE_MAX] = {0};
43 
44 static void HdfI2cInit(I2C_HANDLE i2cx, unsigned int i2cRate, unsigned int addr);
45 static void HdfI2cWrite(I2C_HANDLE i2cx, unsigned char devAddr, const unsigned char *buf, unsigned int len);
46 static void HdfI2cRead(I2C_HANDLE i2cx, unsigned char devAddr, unsigned char *buf, unsigned int len);
47 
48 static int32_t I2cDriverBind(struct HdfDeviceObject *device);
49 static int32_t I2cDriverInit(struct HdfDeviceObject *device);
50 static void I2cDriverRelease(struct HdfDeviceObject *device);
51 static int32_t I2cDataTransfer(struct I2cCntlr *cntlr, struct I2cMsg *msgs, int16_t count);
52 
53 struct HdfDriverEntry gI2cHdfDriverEntry = {
54     .moduleVersion = 1,
55     .moduleName = "HDF_I2C",
56     .Bind = I2cDriverBind,
57     .Init = I2cDriverInit,
58     .Release = I2cDriverRelease,
59 };
60 HDF_INIT(gI2cHdfDriverEntry);
61 
62 struct I2cMethod gI2cHostMethod = {
63     .transfer = I2cDataTransfer,
64 };
65 
66 #ifdef LOSCFG_DRIVERS_HDF_CONFIG_MACRO
67 #define I2C_FIND_CONFIG(node, name, resource) \
68     do { \
69         if (strcmp(HCS_PROP(node, match_attr), name) == 0) { \
70             resource->port = HCS_PROP(node, port); \
71             resource->devMode = HCS_PROP(node, devMode); \
72             resource->devAddr = HCS_PROP(node, devAddr); \
73             resource->speed = HCS_PROP(node, speed); \
74             result = HDF_SUCCESS; \
75         } \
76     } while (0)
77 #define PLATFORM_CONFIG HCS_NODE(HCS_ROOT, platform)
78 #define PLATFORM_I2C_CONFIG HCS_NODE(HCS_NODE(HCS_ROOT, platform), i2c_config)
GetI2cDeviceResource(struct RealI2cResource * i2cResource,const char * deviceMatchAttr)79 static uint32_t GetI2cDeviceResource(struct RealI2cResource *i2cResource, const char *deviceMatchAttr)
80 {
81     int32_t result = HDF_FAILURE;
82     struct RealI2cResource *resource = NULL;
83     if (i2cResource == NULL || deviceMatchAttr == NULL) {
84         HDF_LOGE("device or deviceMatchAttr is NULL\r\n");
85         return HDF_ERR_INVALID_PARAM;
86     }
87     resource = i2cResource;
88 #if HCS_NODE_HAS_PROP(PLATFORM_CONFIG, i2c_config)
89     HCS_FOREACH_CHILD_VARGS(PLATFORM_I2C_CONFIG, I2C_FIND_CONFIG, deviceMatchAttr, resource);
90 #endif
91     if (result != HDF_SUCCESS) {
92         HDF_LOGE("resourceNode %s is NULL\r\n", deviceMatchAttr);
93     } else {
94         HdfI2cInit(i2cResource->port, i2cResource->speed, i2cResource->devAddr);
95     }
96     return result;
97 }
98 #else
GetI2cDeviceResource(struct RealI2cResource * i2cResource,const struct DeviceResourceNode * resourceNode)99 static int32_t GetI2cDeviceResource(struct RealI2cResource *i2cResource, const struct DeviceResourceNode *resourceNode)
100 {
101     if (i2cResource == NULL || resourceNode == NULL) {
102         HDF_LOGE("[%s]: param is NULL\r\n", __func__);
103         return HDF_ERR_INVALID_PARAM;
104     }
105 
106     struct DeviceResourceIface *dri = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);
107     if (dri == NULL || dri->GetUint8 == NULL || dri->GetUint32 == NULL || dri->GetUint32Array == NULL) {
108         HDF_LOGE("DeviceResourceIface is invalid\r\n");
109         return HDF_ERR_INVALID_OBJECT;
110     }
111 
112     if (dri->GetUint8(resourceNode, "port", &i2cResource->port, 0) != HDF_SUCCESS) {
113         HDF_LOGE("i2c config port fail\r\n");
114         return HDF_FAILURE;
115     }
116 
117     if (dri->GetUint8(resourceNode, "devMode", &i2cResource->devMode, 0) != HDF_SUCCESS) {
118         HDF_LOGE("i2c config devMode fail\r\n");
119         return HDF_FAILURE;
120     }
121 
122     if (dri->GetUint32(resourceNode, "devAddr", &i2cResource->devAddr, 0) != HDF_SUCCESS) {
123         HDF_LOGE("i2c config devAddr fail\r\n");
124         return HDF_FAILURE;
125     }
126 
127     if (dri->GetUint32(resourceNode, "speed", &i2cResource->speed, 0) != HDF_SUCCESS) {
128         HDF_LOGE("i2c config speed fail\r\n");
129         return HDF_FAILURE;
130     }
131 
132     HdfI2cInit(i2cResource->port, i2cResource->speed, i2cResource->devAddr);
133 
134     return HDF_SUCCESS;
135 }
136 #endif
137 
AttachI2cDevice(struct I2cCntlr * host,const struct HdfDeviceObject * device)138 static int32_t AttachI2cDevice(struct I2cCntlr *host, const struct HdfDeviceObject *device)
139 {
140     int32_t ret = HDF_FAILURE;
141 
142     if (host == NULL || device == NULL) {
143         HDF_LOGE("[%s]: param is NULL\r\n", __func__);
144         return HDF_ERR_INVALID_PARAM;
145     }
146 
147     struct RealI2cResource *i2cResource = (struct RealI2cResource *)OsalMemAlloc(sizeof(struct RealI2cResource));
148     if (i2cResource == NULL) {
149         HDF_LOGE("[%s]: OsalMemAlloc RealI2cResource fail\r\n", __func__);
150         return HDF_ERR_MALLOC_FAIL;
151     }
152     (void)memset_s(i2cResource, sizeof(struct RealI2cResource), 0, sizeof(struct RealI2cResource));
153 #ifdef LOSCFG_DRIVERS_HDF_CONFIG_MACRO
154     ret = GetI2cDeviceResource(i2cResource, device->deviceMatchAttr);
155 #else
156     ret = GetI2cDeviceResource(i2cResource, device->property);
157 #endif
158     if (ret != HDF_SUCCESS) {
159         OsalMemFree(i2cResource);
160         return HDF_FAILURE;
161     }
162 
163     host->busId = i2cResource->port;
164     host->priv = i2cResource;
165 
166     return HDF_SUCCESS;
167 }
168 
I2cDataTransfer(struct I2cCntlr * cntlr,struct I2cMsg * msgs,int16_t count)169 static int32_t I2cDataTransfer(struct I2cCntlr *cntlr, struct I2cMsg *msgs, int16_t count)
170 {
171     if (cntlr == NULL || msgs == NULL || cntlr->priv == NULL) {
172         HDF_LOGE("[%s]: I2cDataTransfer param is NULL\r\n", __func__);
173         return HDF_ERR_INVALID_PARAM;
174     }
175 
176     if (count <= 0) {
177         HDF_LOGE("[%s]: I2cDataTransfer count err\r\n", __func__);
178         return HDF_ERR_INVALID_PARAM;
179     }
180 
181     struct RealI2cResource *device = (struct I2cDevice *)cntlr->priv;
182     struct I2cMsg *msg = NULL;
183     if (HDF_SUCCESS != OsalMutexLock(&device->mutex)) {
184         HDF_LOGE("[%s]: OsalMutexLock fail\r\n", __func__);
185         return HDF_ERR_TIMEOUT;
186     }
187 
188     for (int32_t i = 0; i < count; i++) {
189         msg = &msgs[i];
190         if (msg->flags == I2C_FLAG_READ) {
191             HdfI2cRead(device->port, msg->addr, msg->buf, msg->len);
192         } else {
193             HdfI2cWrite(device->port, msg->addr, msg->buf, msg->len);
194         }
195     }
196     OsalMutexUnlock(&device->mutex);
197 
198     return count;
199 }
200 
I2cDriverBind(struct HdfDeviceObject * device)201 static int32_t I2cDriverBind(struct HdfDeviceObject *device)
202 {
203     if (device == NULL) {
204         HDF_LOGE("[%s]: I2c device is NULL\r\n", __func__);
205         return HDF_FAILURE;
206     }
207     return HDF_SUCCESS;
208 }
209 
I2cDriverInit(struct HdfDeviceObject * device)210 static int32_t I2cDriverInit(struct HdfDeviceObject *device)
211 {
212     int32_t ret = HDF_FAILURE;
213     struct I2cCntlr *host = NULL;
214     if (device == NULL) {
215         HDF_LOGE("[%s]: I2c device is NULL\r\n", __func__);
216         return HDF_ERR_INVALID_PARAM;
217     }
218 
219     host = (struct I2cCntlr *)OsalMemAlloc(sizeof(struct I2cCntlr));
220     if (host == NULL) {
221         HDF_LOGE("[%s]: malloc host is NULL\r\n", __func__);
222         return HDF_ERR_MALLOC_FAIL;
223     }
224 
225     (void)memset_s(host, sizeof(struct I2cCntlr), 0, sizeof(struct I2cCntlr));
226     host->ops = &gI2cHostMethod;
227     device->priv = (void *)host;
228 
229     ret = AttachI2cDevice(host, device);
230     if (ret != HDF_SUCCESS) {
231         HDF_LOGE("[%s]: AttachI2cDevice error, ret = %d\r\n", __func__, ret);
232         I2cDriverRelease(device);
233         return HDF_DEV_ERR_ATTACHDEV_FAIL;
234     }
235 
236     ret = I2cCntlrAdd(host);
237     if (ret != HDF_SUCCESS) {
238         I2cDriverRelease(device);
239         return HDF_FAILURE;
240     }
241 
242     return HDF_SUCCESS;
243 }
244 
I2cDriverRelease(struct HdfDeviceObject * device)245 static void I2cDriverRelease(struct HdfDeviceObject *device)
246 {
247     if (device == NULL) {
248         HDF_LOGE("%s: device is NULL\r\n", __func__);
249         return;
250     }
251 
252     struct I2cCntlr *i2cCntrl = device->priv;
253     if (i2cCntrl == NULL || i2cCntrl->priv == NULL) {
254         HDF_LOGE("%s: i2cCntrl is NULL\r\n", __func__);
255         return;
256     }
257     i2cCntrl->ops = NULL;
258     struct RealI2cResource *i2cDevice = (struct I2cDevice *)i2cCntrl->priv;
259     OsalMemFree(i2cCntrl);
260 
261     if (i2cDevice != NULL) {
262         OsalMutexDestroy(&i2cDevice->mutex);
263         OsalMemFree(i2cDevice);
264     }
265 }
266 
GetLLI2cHandlerMatch(I2C_HANDLE i2cx)267 static I2C_TypeDef *GetLLI2cHandlerMatch(I2C_HANDLE i2cx)
268 {
269     if (i2cx > I2C_HANDLE_MAX) {
270         printf("ERR: GetLLI2cClkMatch fail, param match fail\r\n");
271         return NULL;
272     }
273 
274     switch (i2cx) {
275         case I2C_HANDLE_1:
276             return (I2C_TypeDef *)I2C1;
277         case I2C_HANDLE_2:
278             return (I2C_TypeDef *)I2C2;
279         case I2C_HANDLE_3:
280             return (I2C_TypeDef *)I2C3;
281         default:
282             printf("ERR: GetLLI2cClkMatch fail, handler match fail\r\n");
283             return NULL;
284     }
285 }
286 
EnableLLI2cClock(const I2C_TypeDef * i2cx)287 static bool EnableLLI2cClock(const I2C_TypeDef *i2cx)
288 {
289     if (i2cx == I2C1) {
290         LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_I2C1);
291         return true;
292     } else if (i2cx == I2C2) {
293         LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_I2C2);
294         return true;
295     } else if (i2cx == I2C3) {
296         LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_I2C3);
297         return true;
298     } else {
299         printf("EnableI2cClock fail, i2cx match fail\r\n");
300         return false;
301     }
302 }
303 
HdfI2cInit(I2C_HANDLE i2cx,unsigned int i2cRate,unsigned int addr)304 static void HdfI2cInit(I2C_HANDLE i2cx, unsigned int i2cRate, unsigned int addr)
305 {
306     LL_I2C_InitTypeDef I2C_InitStruct = {0};
307     I2C_TypeDef *myI2c = GetLLI2cHandlerMatch(i2cx);
308     if (myI2c == NULL) {
309         return;
310     }
311 
312     EnableLLI2cClock(myI2c);
313     LL_I2C_DisableOwnAddress2(myI2c);
314     LL_I2C_DisableGeneralCall(myI2c);
315     LL_I2C_EnableClockStretching(myI2c);
316     I2C_InitStruct.PeripheralMode = LL_I2C_MODE_I2C;
317     I2C_InitStruct.ClockSpeed = i2cRate;
318     I2C_InitStruct.DutyCycle = LL_I2C_DUTYCYCLE_2;
319     I2C_InitStruct.OwnAddress1 = addr;
320     I2C_InitStruct.TypeAcknowledge = LL_I2C_ACK;
321     I2C_InitStruct.OwnAddrSize = LL_I2C_OWNADDRESS1_7BIT;
322     LL_I2C_Init(myI2c, &I2C_InitStruct);
323     LL_I2C_SetOwnAddress2(myI2c, 0);
324 
325     g_I2cEnableFlg[i2cx] = true;
326 }
327 
HdfI2cWrite(I2C_HANDLE i2cx,unsigned char devAddr,const unsigned char * buf,unsigned int len)328 static void HdfI2cWrite(I2C_HANDLE i2cx, unsigned char devAddr, const unsigned char *buf, unsigned int len)
329 {
330     if (g_I2cEnableFlg[i2cx] != true) {
331         printf("I2C_WriteByte err, Please initialize first!");
332         return;
333     }
334 
335     I2C_TypeDef *myI2c = GetLLI2cHandlerMatch(i2cx);
336     if (myI2c == NULL) {
337         return;
338     }
339 
340     while (LL_I2C_IsActiveFlag_BUSY(myI2c)) { }
341 
342     LL_I2C_GenerateStartCondition(myI2c);
343     while (LL_I2C_IsActiveFlag_SB(myI2c) == RESET) { }
344 
345     LL_I2C_TransmitData8(myI2c, (devAddr << 1));
346     while (LL_I2C_IsActiveFlag_TXE(myI2c) == RESET) { }
347 
348     LL_I2C_ClearFlag_ADDR(myI2c);
349     while (LL_I2C_IsActiveFlag_TXE(myI2c) == RESET) { }
350 
351     for (unsigned int i = 0; i < len; i++) {
352         LL_I2C_TransmitData8(myI2c, buf[i]);
353         while (LL_I2C_IsActiveFlag_TXE(myI2c) == RESET) { }
354     }
355 
356     LL_I2C_GenerateStopCondition(myI2c);
357 }
358 
HdfI2cRead(I2C_HANDLE i2cx,unsigned char devAddr,unsigned char * buf,unsigned int len)359 static void HdfI2cRead(I2C_HANDLE i2cx, unsigned char devAddr, unsigned char *buf, unsigned int len)
360 {
361     if (g_I2cEnableFlg[i2cx] != true) {
362         printf("I2C_ReadByte err, Please initialize first!");
363         return;
364     }
365 
366     I2C_TypeDef *myI2c = GetLLI2cHandlerMatch(i2cx);
367     if (myI2c == NULL) {
368         return;
369     }
370 
371     while (LL_I2C_IsActiveFlag_BUSY(myI2c)) { }
372 
373     LL_I2C_GenerateStartCondition(myI2c);
374     while (LL_I2C_IsActiveFlag_SB(myI2c) == RESET) { }
375 
376     LL_I2C_TransmitData8(myI2c, ((devAddr << 1) | 1));
377     while ((LL_I2C_IsActiveFlag_ADDR(myI2c) == RESET) || (LL_I2C_IsActiveFlag_MSL(myI2c) == RESET) ||
378         (LL_I2C_IsActiveFlag_BUSY(myI2c) == RESET)) { }
379 
380     for (unsigned int i = 0; i < len; i++) {
381         if (i < len - 1) {
382             LL_I2C_AcknowledgeNextData(myI2c, LL_I2C_ACK);
383         } else {
384             LL_I2C_AcknowledgeNextData(myI2c, LL_I2C_NACK);
385         }
386         while (LL_I2C_IsActiveFlag_RXNE(myI2c) == RESET) { }
387         buf[i] = LL_I2C_ReceiveData8(myI2c);
388     }
389     LL_I2C_GenerateStopCondition(myI2c);
390 }
391